refactor: update email templates to use dynamic logo URLs and standardize branding to RE-Quest

This commit is contained in:
pradeepkumar committed 2026-04-09 21:34:04 +05:30
1 parent 92a29b664c
commit d80f75a39e
5 files changed
+33 -53

No files matched your search

+8 -7
View File
@@ -71,12 +71,12 @@ export class EmailService {
const frontendUrl = this.configService.get<string>('FRONTEND_URL') || 'http://localhost:3000'; const frontendUrl = this.configService.get<string>('FRONTEND_URL') || 'http://localhost:3000';
const verificationUrl = `${frontendUrl}/verify-email?token=${token}`; const verificationUrl = `${frontendUrl}/verify-email?token=${token}`;
const html = getVerificationEmailTemplate({ verificationUrl, name }); const html = getVerificationEmailTemplate({ verificationUrl, name, frontendUrl });
const text = `Welcome to RE-QuestN! Please verify your email by clicking this link: ${verificationUrl}`; const text = `Welcome to RE-Quest! Please verify your email by clicking this link: ${verificationUrl}`;
return this.sendEmail({ return this.sendEmail({
to: email, to: email,
subject: 'Verify Your Email - RE-QuestN', subject: 'Verify Your Email - RE-Quest',
html, html,
text, text,
}); });
@@ -86,12 +86,13 @@ export class EmailService {
// PASSWORD RESET // PASSWORD RESET
// ========================================== // ==========================================
async sendPasswordResetEmail(email: string, resetUrl: string): Promise<boolean> { async sendPasswordResetEmail(email: string, resetUrl: string): Promise<boolean> {
const html = getPasswordResetTemplate({ resetUrl }); const frontendUrl = this.configService.get<string>('FRONTEND_URL') || 'http://localhost:3000';
const html = getPasswordResetTemplate({ resetUrl, frontendUrl });
const text = `Reset your password by clicking this link: ${resetUrl}. This link will expire in 1 hour.`; const text = `Reset your password by clicking this link: ${resetUrl}. This link will expire in 1 hour.`;
return this.sendEmail({ return this.sendEmail({
to: email, to: email,
subject: 'Reset Your Password - RE-QuestN', subject: 'Reset Your Password - RE-Quest',
html, html,
text, text,
}); });
@@ -103,11 +104,11 @@ export class EmailService {
async sendWelcomeEmail(email: string, name?: string): Promise<boolean> { async sendWelcomeEmail(email: string, name?: string): Promise<boolean> {
const frontendUrl = this.configService.get<string>('FRONTEND_URL') || 'http://localhost:3000'; const frontendUrl = this.configService.get<string>('FRONTEND_URL') || 'http://localhost:3000';
const html = getWelcomeEmailTemplate({ name, frontendUrl }); const html = getWelcomeEmailTemplate({ name, frontendUrl });
const text = `Welcome to RE-QuestN, ${name || 'User'}! Your real estate journey starts now.`; const text = `Welcome to RE-Quest, ${name || 'User'}! Your real estate journey starts now.`;
return this.sendEmail({ return this.sendEmail({
to: email, to: email,
subject: 'Welcome to RE-QuestN!', subject: 'Welcome to RE-Quest!',
html, html,
text, text,
}); });
+10 -36
View File
@@ -1,34 +1,20 @@
/** /**
* Base HTML email template with RE-QuestN branding * Base HTML email template with RE-Quest branding
* All email templates use this as their foundation * All email templates use this as their foundation
* *
* Using styled text logo for maximum email client compatibility * Uses the actual RE-Quest logo image hosted on the frontend
*/ */
function getLogo(): string { export function getBaseTemplate(content: string, logoUrl?: string): string {
// Styled text logo - works in ALL email clients (Gmail, Outlook, Apple Mail, etc.) const logoSrc = logoUrl || 'https://prod.re-quest.com/assets/images/splash-logo.png';
return `
<svg width="121" height="32" viewBox="0 0 121 32" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="121" height="32" fill="url(#pattern0_1_17594)"/>
<defs>
<pattern id="pattern0_1_17594" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_1_17594" transform="matrix(0.000465766 0 0 0.00181316 0 0.0938519)"/>
</pattern>
<image id="image0_1_17594" width="2147" height="448" preserveAspectRatio="none" xlink:href="data:image/png;base64,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 Line truncated
</defs>
</svg>
`;
}
export function getBaseTemplate(content: string): string {
return ` return `
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RE-QuestN</title> <title>RE-Quest</title>
<style> <style>
body { body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
@@ -57,19 +43,9 @@ export function getBaseTemplate(content: string): string {
text-align: center; text-align: center;
margin-bottom: 30px; margin-bottom: 30px;
} }
.logo-text { .logo img {
font-size: 28px; max-width: 200px;
font-weight: 600; height: auto;
}
.logo-re {
color: #00293d;
}
.logo-quest {
color: #5ba4a4;
}
.logo-n {
color: #e58625;
text-decoration: underline;
} }
h1 { h1 {
color: #00293d; color: #00293d;
@@ -134,13 +110,11 @@ export function getBaseTemplate(content: string): string {
<div class="container"> <div class="container">
<div class="email-content"> <div class="email-content">
<div class="logo"> <div class="logo">
<span class="logo-text"> <img src="${logoSrc}" alt="RE-Quest" width="200" />
<span class="logo-re">RE-</span><span class="logo-quest">Quest</span><span class="logo-n">N</span>
</span>
</div> </div>
${content} ${content}
<div class="footer"> <div class="footer">
<p>&copy; ${new Date().getFullYear()} RE-QuestN. All rights reserved.</p> <p>&copy; ${new Date().getFullYear()} RE-Quest. All rights reserved.</p>
<p>Your trusted real estate platform</p> <p>Your trusted real estate platform</p>
</div> </div>
</div> </div>
@@ -6,15 +6,17 @@ import { getBaseTemplate } from './base.template';
*/ */
export interface PasswordResetTemplateData { export interface PasswordResetTemplateData {
resetUrl: string; resetUrl: string;
frontendUrl?: string;
} }
export function getPasswordResetTemplate(data: PasswordResetTemplateData): string { export function getPasswordResetTemplate(data: PasswordResetTemplateData): string {
const { resetUrl } = data; const { resetUrl, frontendUrl } = data;
const logoUrl = frontendUrl ? `${frontendUrl}/assets/images/splash-logo.png` : undefined;
const content = ` const content = `
<h1>Reset Your Password</h1> <h1>Reset Your Password</h1>
<p>Hi,</p> <p>Hi,</p>
<p>We received a request to reset your password for your RE-QuestN account. Click the button below to create a new password:</p> <p>We received a request to reset your password for your RE-Quest account. Click the button below to create a new password:</p>
<div class="button-container"> <div class="button-container">
<a href="${resetUrl}" class="button">Reset Password</a> <a href="${resetUrl}" class="button">Reset Password</a>
</div> </div>
@@ -25,5 +27,5 @@ export function getPasswordResetTemplate(data: PasswordResetTemplateData): strin
</div> </div>
`; `;
return getBaseTemplate(content); return getBaseTemplate(content, logoUrl);
} }
+6 -4
View File
@@ -7,24 +7,26 @@ import { getBaseTemplate } from './base.template';
export interface VerificationTemplateData { export interface VerificationTemplateData {
verificationUrl: string; verificationUrl: string;
name?: string; name?: string;
frontendUrl?: string;
} }
export function getVerificationEmailTemplate(data: VerificationTemplateData): string { export function getVerificationEmailTemplate(data: VerificationTemplateData): string {
const { verificationUrl, name } = data; const { verificationUrl, name, frontendUrl } = data;
const logoUrl = frontendUrl ? `${frontendUrl}/assets/images/splash-logo.png` : undefined;
const content = ` const content = `
<h1>Verify Your Email</h1> <h1>Verify Your Email</h1>
<p>Hi ${name || 'there'},</p> <p>Hi ${name || 'there'},</p>
<p>Thank you for signing up for RE-QuestN! To complete your registration and start your real estate journey, please verify your email address by clicking the button below:</p> <p>Thank you for signing up for RE-Quest! To complete your registration and start your real estate journey, please verify your email address by clicking the button below:</p>
<div class="button-container"> <div class="button-container">
<a href="${verificationUrl}" class="button">Verify Email</a> <a href="${verificationUrl}" class="button">Verify Email</a>
</div> </div>
<p>Or copy and paste this link into your browser:</p> <p>Or copy and paste this link into your browser:</p>
<p style="word-break: break-all; font-size: 14px; color: #5ba4a4;">${verificationUrl}</p> <p style="word-break: break-all; font-size: 14px; color: #5ba4a4;">${verificationUrl}</p>
<div class="note"> <div class="note">
<strong>Note:</strong> This verification link will expire in 24 hours. If you didn't create an account with RE-QuestN, please ignore this email. <strong>Note:</strong> This verification link will expire in 24 hours. If you didn't create an account with RE-Quest, please ignore this email.
</div> </div>
`; `;
return getBaseTemplate(content); return getBaseTemplate(content, logoUrl);
} }
+4 -3
View File
@@ -11,11 +11,12 @@ export interface WelcomeTemplateData {
export function getWelcomeEmailTemplate(data: WelcomeTemplateData): string { export function getWelcomeEmailTemplate(data: WelcomeTemplateData): string {
const { name, frontendUrl } = data; const { name, frontendUrl } = data;
const logoUrl = frontendUrl ? `${frontendUrl}/assets/images/splash-logo.png` : undefined;
const content = ` const content = `
<h1>Welcome to RE-QuestN!</h1> <h1>Welcome to RE-Quest!</h1>
<p>Hi ${name || 'there'},</p> <p>Hi ${name || 'there'},</p>
<p>We're thrilled to have you join RE-QuestN - your trusted real estate platform!</p> <p>We're thrilled to have you join RE-Quest - your trusted real estate platform!</p>
<p>Here's what you can do:</p> <p>Here's what you can do:</p>
<ul> <ul>
<li>Browse thousands of property listings</li> <li>Browse thousands of property listings</li>
@@ -29,5 +30,5 @@ export function getWelcomeEmailTemplate(data: WelcomeTemplateData): string {
<p>If you have any questions, our support team is always here to help!</p> <p>If you have any questions, our support team is always here to help!</p>
`; `;
return getBaseTemplate(content); return getBaseTemplate(content, logoUrl);
} }