summaryrefslogtreecommitdiff
path: root/lib/mail
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mail')
-rw-r--r--lib/mail/mailer.ts146
-rw-r--r--lib/mail/sendEmail.ts15
-rw-r--r--lib/mail/templates/letter-of-regret.hbs190
3 files changed, 304 insertions, 47 deletions
diff --git a/lib/mail/mailer.ts b/lib/mail/mailer.ts
index 61201e99..0387d7dd 100644
--- a/lib/mail/mailer.ts
+++ b/lib/mail/mailer.ts
@@ -23,54 +23,96 @@ function registerHandlebarsHelpers() {
return i18next.t(key, options.hash || {});
});
- // eq 헬퍼 등록 - 두 값을 비교 (블록 헬퍼)
- handlebars.registerHelper('eq', function(a: any, b: any, options: any) {
- if (a === b) {
- return options.fn(this);
- } else {
- return options.inverse(this);
+ // eq 헬퍼 등록 - 인라인과 블록 헬퍼 둘 다 지원
+ handlebars.registerHelper('eq', function(a: any, b: any, options?: any) {
+ const result = a === b;
+
+ // 블록 헬퍼로 사용된 경우 (options가 있고 fn 함수가 있는 경우)
+ if (options && typeof options.fn === 'function') {
+ if (result) {
+ return options.fn(this);
+ } else {
+ return options.inverse(this);
+ }
}
+
+ // 인라인 헬퍼로 사용된 경우
+ return result;
});
- // 기타 유용한 헬퍼들
- handlebars.registerHelper('ne', function(a: any, b: any, options: any) {
- if (a !== b) {
- return options.fn(this);
- } else {
- return options.inverse(this);
+ // ne 헬퍼 - 인라인과 블록 헬퍼 둘 다 지원
+ handlebars.registerHelper('ne', function(a: any, b: any, options?: any) {
+ const result = a !== b;
+
+ if (options && typeof options.fn === 'function') {
+ if (result) {
+ return options.fn(this);
+ } else {
+ return options.inverse(this);
+ }
}
+
+ return result;
});
- handlebars.registerHelper('gt', function(a: any, b: any, options: any) {
- if (a > b) {
- return options.fn(this);
- } else {
- return options.inverse(this);
+ // gt 헬퍼 - 인라인과 블록 헬퍼 둘 다 지원
+ handlebars.registerHelper('gt', function(a: any, b: any, options?: any) {
+ const result = a > b;
+
+ if (options && typeof options.fn === 'function') {
+ if (result) {
+ return options.fn(this);
+ } else {
+ return options.inverse(this);
+ }
}
+
+ return result;
});
- handlebars.registerHelper('gte', function(a: any, b: any, options: any) {
- if (a >= b) {
- return options.fn(this);
- } else {
- return options.inverse(this);
+ // gte 헬퍼 - 인라인과 블록 헬퍼 둘 다 지원
+ handlebars.registerHelper('gte', function(a: any, b: any, options?: any) {
+ const result = a >= b;
+
+ if (options && typeof options.fn === 'function') {
+ if (result) {
+ return options.fn(this);
+ } else {
+ return options.inverse(this);
+ }
}
+
+ return result;
});
- handlebars.registerHelper('lt', function(a: any, b: any, options: any) {
- if (a < b) {
- return options.fn(this);
- } else {
- return options.inverse(this);
+ // lt 헬퍼 - 인라인과 블록 헬퍼 둘 다 지원
+ handlebars.registerHelper('lt', function(a: any, b: any, options?: any) {
+ const result = a < b;
+
+ if (options && typeof options.fn === 'function') {
+ if (result) {
+ return options.fn(this);
+ } else {
+ return options.inverse(this);
+ }
}
+
+ return result;
});
- handlebars.registerHelper('lte', function(a: any, b: any, options: any) {
- if (a <= b) {
- return options.fn(this);
- } else {
- return options.inverse(this);
+ // lte 헬퍼 - 인라인과 블록 헬퍼 둘 다 지원
+ handlebars.registerHelper('lte', function(a: any, b: any, options?: any) {
+ const result = a <= b;
+
+ if (options && typeof options.fn === 'function') {
+ if (result) {
+ return options.fn(this);
+ } else {
+ return options.inverse(this);
+ }
}
+
+ return result;
});
// and 헬퍼 - 모든 조건이 true인지 확인 (블록 헬퍼)
@@ -78,12 +120,17 @@ function registerHandlebarsHelpers() {
// 마지막 인자는 Handlebars 옵션
const options = args[args.length - 1];
const values = args.slice(0, -1);
+ const result = values.every(Boolean);
- if (values.every(Boolean)) {
- return options.fn(this);
- } else {
- return options.inverse(this);
+ if (typeof options.fn === 'function') {
+ if (result) {
+ return options.fn(this);
+ } else {
+ return options.inverse(this);
+ }
}
+
+ return result;
});
// or 헬퍼 - 하나라도 true인지 확인 (블록 헬퍼)
@@ -91,21 +138,32 @@ function registerHandlebarsHelpers() {
// 마지막 인자는 Handlebars 옵션
const options = args[args.length - 1];
const values = args.slice(0, -1);
+ const result = values.some(Boolean);
- if (values.some(Boolean)) {
- return options.fn(this);
- } else {
- return options.inverse(this);
+ if (typeof options.fn === 'function') {
+ if (result) {
+ return options.fn(this);
+ } else {
+ return options.inverse(this);
+ }
}
+
+ return result;
});
// not 헬퍼 - 값 반전 (블록 헬퍼)
handlebars.registerHelper('not', function(value: any, options: any) {
- if (!value) {
- return options.fn(this);
- } else {
- return options.inverse(this);
+ const result = !value;
+
+ if (typeof options.fn === 'function') {
+ if (result) {
+ return options.fn(this);
+ } else {
+ return options.inverse(this);
+ }
}
+
+ return result;
});
// formatDate 헬퍼 - 날짜 포맷팅
diff --git a/lib/mail/sendEmail.ts b/lib/mail/sendEmail.ts
index 3f88cb04..b4d2707a 100644
--- a/lib/mail/sendEmail.ts
+++ b/lib/mail/sendEmail.ts
@@ -29,14 +29,23 @@ export async function sendEmail({
// i18n 설정
const { t, i18n } = await useTranslation(context.language ?? "en", "translation");
- // t 헬퍼만 동적으로 등록 (이미 mailer.ts에서 기본 등록되어 있지만, 언어별로 다시 등록)
+ // t 헬퍼를 언어별로 동적으로 재등록 (기존 헬퍼 덮어쓰기)
+ // 헬퍼가 이미 등록되어 있더라도 안전하게 재등록
+ handlebars.unregisterHelper('t'); // 기존 헬퍼 제거
handlebars.registerHelper("t", function (key: string, options: any) {
// 여기서 i18n은 로컬 인스턴스
- return i18n.t(key, options.hash || {});
+ return i18n.t(key, options?.hash || {});
});
+ // 템플릿 데이터에 i18n 인스턴스와 번역 함수 추가
+ const templateData = {
+ ...context,
+ t: (key: string, options?: any) => i18n.t(key, options || {}),
+ i18n: i18n
+ };
+
// 템플릿 컴파일 및 HTML 생성
- const html = loadTemplate(template, context);
+ const html = loadTemplate(template, templateData);
// 이메일 발송
const result = await transporter.sendMail({
diff --git a/lib/mail/templates/letter-of-regret.hbs b/lib/mail/templates/letter-of-regret.hbs
new file mode 100644
index 00000000..13fab6fc
--- /dev/null
+++ b/lib/mail/templates/letter-of-regret.hbs
@@ -0,0 +1,190 @@
+<!DOCTYPE html>
+<html lang="{{#if (eq language 'ko')}}ko{{else}}en{{/if}}">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>{{#if (eq language 'ko')}}Letter of Regret{{else}}Letter of Regret{{/if}}</title>
+ <style>
+ body {
+ font-family: 'Arial', sans-serif;
+ line-height: 1.6;
+ color: #333;
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 20px;
+ background-color: #f9f9f9;
+ }
+ .container {
+ background-color: white;
+ padding: 40px;
+ border-radius: 8px;
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+ }
+ .header {
+ text-align: center;
+ border-bottom: 2px solid #e74c3c;
+ padding-bottom: 20px;
+ margin-bottom: 30px;
+ }
+ .company-logo {
+ font-size: 24px;
+ font-weight: bold;
+ color: #2c3e50;
+ margin-bottom: 10px;
+ }
+ .letter-title {
+ font-size: 20px;
+ color: #e74c3c;
+ font-weight: bold;
+ margin: 0;
+ }
+ .content {
+ margin-bottom: 30px;
+ }
+ .greeting {
+ font-weight: bold;
+ margin-bottom: 20px;
+ font-size: 16px;
+ }
+ .body-text {
+ margin-bottom: 15px;
+ text-align: justify;
+ }
+ .project-info {
+ background-color: #f8f9fa;
+ padding: 15px;
+ border-left: 4px solid #e74c3c;
+ margin: 20px 0;
+ }
+ .project-info strong {
+ color: #2c3e50;
+ }
+ .closing {
+ margin-top: 30px;
+ }
+ .signature {
+ margin-top: 40px;
+ border-top: 1px solid #ddd;
+ padding-top: 20px;
+ }
+ .signature-line {
+ margin-bottom: 5px;
+ }
+ .footer {
+ margin-top: 30px;
+ padding-top: 20px;
+ border-top: 1px solid #ddd;
+ font-size: 12px;
+ color: #666;
+ text-align: center;
+ }
+ .highlight {
+ color: #e74c3c;
+ font-weight: bold;
+ }
+ </style>
+</head>
+<body>
+ <div class="container">
+ <div class="header">
+ <div class="company-logo">{{companyName}}</div>
+ <h1 class="letter-title">
+ {{#if (eq language 'ko')}}
+ 협력 제안 결과 안내서 (Letter of Regret)
+ {{else}}
+ Letter of Regret
+ {{/if}}
+ </h1>
+ </div>
+
+ <div class="content">
+ <div class="greeting">
+ {{#if (eq language 'ko')}}
+ {{vendorName}} 귀하
+ {{else}}
+ Dear {{vendorName}},
+ {{/if}}
+ </div>
+
+ <div class="body-text">
+ {{#if (eq language 'ko')}}
+ 안녕하십니까. {{companyName}}입니다.
+ {{else}}
+ Greetings from {{companyName}}.
+ {{/if}}
+ </div>
+
+ <div class="body-text">
+ {{#if (eq language 'ko')}}
+ 먼저 저희 프로젝트에 관심을 가져주시고 귀중한 시간을 할애하여 RFQ에 응답해 주신 점에 대해 깊이 감사드립니다.
+ {{else}}
+ First, we would like to express our sincere gratitude for your interest in our project and for taking the time to respond to our RFQ.
+ {{/if}}
+ </div>
+
+ <div class="project-info">
+ <strong>
+ {{#if (eq language 'ko')}}프로젝트 정보{{else}}Project Information{{/if}}:
+ </strong><br>
+ <strong>RFQ {{#if (eq language 'ko')}}번호{{else}}Number{{/if}}:</strong> {{rfqCode}}<br>
+ <strong>{{#if (eq language 'ko')}}프로젝트명{{else}}Project Title{{/if}}:</strong> {{projectTitle}}<br>
+ <strong>{{#if (eq language 'ko')}}통지일{{else}}Notification Date{{/if}}:</strong> {{dateTime}}
+ </div>
+
+ <div class="body-text">
+ {{#if (eq language 'ko')}}
+ 신중한 검토와 평가를 거쳐 진행한 결과, 아쉽게도 이번 프로젝트에서는 다른 업체와 함께 진행하기로 결정하였음을 알려드립니다.
+ {{else}}
+ After careful review and evaluation, we regret to inform you that we have decided to proceed with another vendor for this project.
+ {{/if}}
+ </div>
+
+ <div class="body-text">
+ {{#if (eq language 'ko')}}
+ 이번 결정이 귀하의 기술력이나 역량에 대한 평가와는 무관함을 말씀드리며, 향후 다른 프로젝트에서 함께 할 수 있는 기회가 있기를 기대합니다.
+ {{else}}
+ Please note that this decision is not a reflection of your technical capabilities or competence, and we look forward to potential collaboration opportunities in future projects.
+ {{/if}}
+ </div>
+
+ <div class="body-text">
+ {{#if (eq language 'ko')}}
+ 다시 한번 저희 RFQ에 참여해 주신 것에 대해 진심으로 감사드리며, 앞으로도 지속적인 관심과 협력을 부탁드립니다.
+ {{else}}
+ Once again, we sincerely thank you for your participation in our RFQ process and look forward to your continued interest and cooperation.
+ {{/if}}
+ </div>
+
+ <div class="closing">
+ {{#if (eq language 'ko')}}
+ 감사합니다.
+ {{else}}
+ Thank you for your understanding.
+ {{/if}}
+ </div>
+ </div>
+
+ <div class="signature">
+ <div class="signature-line">
+ <strong>{{#if (eq language 'ko')}}발신{{else}}From{{/if}}:</strong> {{companyName}}
+ </div>
+ <div class="signature-line">
+ <strong>{{#if (eq language 'ko')}}구매팀{{else}}Procurement Department{{/if}}</strong>
+ </div>
+ <div class="signature-line">
+ <strong>{{#if (eq language 'ko')}}일자{{else}}Date{{/if}}:</strong> {{dateTime}}
+ </div>
+ </div>
+
+ <div class="footer">
+ <p>
+ {{#if (eq language 'ko')}}
+ 본 메일은 자동으로 발송된 메일입니다. 문의사항이 있으시면 담당자에게 직접 연락해 주시기 바랍니다.
+ {{else}}
+ This is an automatically generated email. For any inquiries, please contact the relevant department directly.
+ {{/if}}
+ </p>
+ </div>
+ </div>
+</body>
+</html> \ No newline at end of file