feat: styling email template

This commit is contained in:
Abdalhamid Alhamad
2025-04-06 13:33:57 +03:00
parent a3f88c774c
commit ffca6996fd
8 changed files with 157 additions and 28 deletions

View File

@ -10,8 +10,7 @@
"include": "config",
"exclude": "**/*.md"
},
{ "include": "common/modules/**/templates/*", "watchAssets": true }
,
{ "include": "common/modules/**/templates/**/*", "watchAssets": true },
"i18n",
"files"
]

10
package-lock.json generated
View File

@ -36,6 +36,7 @@
"firebase-admin": "^13.0.2",
"google-libphonenumber": "^3.2.39",
"handlebars": "^4.7.8",
"handlebars-layouts": "^3.1.4",
"jwk-to-pem": "^2.0.7",
"lodash": "^4.17.21",
"moment": "^2.30.1",
@ -6983,6 +6984,15 @@
"uglify-js": "^3.1.4"
}
},
"node_modules/handlebars-layouts": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/handlebars-layouts/-/handlebars-layouts-3.1.4.tgz",
"integrity": "sha512-2llBmvnj8ueOfxNHdRzJOcgalzZjYVd9+WAl93kPYmlX4WGx7FTHTzNxhK+i9YKY2OSjzfehgpLiIwP/OJr6tw==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/handlebars/node_modules/source-map": {
"version": "0.6.1",
"license": "BSD-3-Clause",

View File

@ -54,6 +54,7 @@
"firebase-admin": "^13.0.2",
"google-libphonenumber": "^3.2.39",
"handlebars": "^4.7.8",
"handlebars-layouts": "^3.1.4",
"jwk-to-pem": "^2.0.7",
"lodash": "^4.17.21",
"moment": "^2.30.1",

View File

@ -72,12 +72,17 @@ export class NotificationCreatedListener {
private async sendEmail({ to, subject, data, template }: SendEmailRequestDto) {
this.logger.log(`Sending email to ${to}`);
await this.mailerService.sendMail({
to,
subject,
template,
context: { ...data },
});
this.logger.log(`Email sent to ${to}`);
try {
await this.mailerService.sendMail({
to,
subject,
template,
context: { ...data, currentYear: new Date().getFullYear() },
});
this.logger.log(`Email sent to ${to}`);
} catch (error) {
this.logger.error(`Failed to send email to ${to} error: ${JSON.stringify(error)}`);
throw error;
}
}
}

View File

@ -1,21 +1,22 @@
<body>
<div class="otp">
<h1 class="title">Your OTP Code</h1>
<p class="message">To verify your account, please use the following One-Time Password (OTP):</p>
{{>header}}
<div class="email-container">
<div class="email-body">
<h2>Your One-Time Password</h2>
<p class="instructions">
Hello! Thank you for using Zod. For security purposes, please use the following
One-Time Password (OTP) to proceed with your verification. This code is
valid for 5 minutes.
</p>
<!-- OTP CODE -->
<div class="otp-code">{{otp}}</div>
<p class="instructions">
If you did not request this code, please ignore this email or
contact our support team immediately.
</p>
</div>
</div>
<style>
.otp {
text-align: center;
font-family: sans-serif;
font-size: 16px;
line-height: 1.5;
}
.otp-code {
font-size: 24px;
font-weight: bold;
margin-top: 20px;
}
</style>
</body>
{{>footer}}

View File

@ -0,0 +1,11 @@
<table class="email-footer" role="presentation" cellpadding="0" cellspacing="0">
<tr>
<td>
<p>
&copy; 2025 Zod. All rights reserved. <br />
Need help? Contact us at
<a href="mailto:support@zod-alkhair.com">support@zod-alkhair.com</a>
</p>
</td>
</tr>
</table>

View File

@ -0,0 +1,95 @@
<head>
<meta charset="UTF-8" />
<title>Zod OTP Email</title>
<style>
/* ----- Core Reset ----- */
body, table, td, a {
font-family: Arial, sans-serif;
text-decoration: none;
}
body {
margin: 0;
padding: 0;
background-color: #F8F8F8;
}
table {
border-collapse: collapse;
width: 100%;
}
/* ----- Header ----- */
.email-header {
background-color: #7B2BFF; /* primary color */
padding: 1rem;
text-align: center;
}
.email-header h1 {
color: #FFFFFF;
margin: 0;
font-size: 1.5rem;
text-transform: uppercase;
letter-spacing: 2px;
}
/* ----- Main Container ----- */
.email-container {
max-width: 600px;
margin: 2rem auto;
background-color: #FFFFFF;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
}
.email-body {
padding: 2rem;
color: #444444;
}
.email-body h2 {
margin-top: 0;
color: #7B2BFF; /* primary color */
}
.otp-code {
margin: 2rem 0;
font-size: 2rem;
font-weight: bold;
color: #1570EF; /* secondary color */
text-align: center;
}
.instructions {
line-height: 1.5;
margin: 1rem 0;
}
.btn-verify {
display: inline-block;
padding: 0.75rem 1.5rem;
background-color: #1570EF; /* secondary color */
color: #FFFFFF;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
margin-top: 1rem;
}
/* ----- Footer ----- */
.email-footer {
background-color: #F8F8F8;
text-align: center;
padding: 1rem;
font-size: 0.875rem;
color: #999999;
}
.email-footer a {
color: #1570EF; /* secondary color */
}
</style>
</head>
<body>
<!-- HEADER -->
<table class="email-header" role="presentation" cellpadding="0" cellspacing="0">
<tr>
<td>
<h1>ZOD</h1>
</td>
</tr>
</table>

View File

@ -1,7 +1,6 @@
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';
import { ConfigService } from '@nestjs/config';
import path from 'path';
export function buildMailerOptions(config: ConfigService) {
return {
transport: {
@ -20,5 +19,13 @@ export function buildMailerOptions(config: ConfigService) {
strict: true,
},
},
options: {
partials: {
dir: path.join(__dirname, '../../common/modules/notification/templates', 'partials'),
options: {
strict: true,
},
},
},
};
}