chore: template
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
import { Injectable, Logger } from "@nestjs/common";
|
||||
|
||||
import { TemplatesService } from "./templates.service";
|
||||
// import { PersonalityDataType, SectionItemType, TextType } from "../interfaces/structure.interface";
|
||||
|
||||
interface ProcessedTemplateResult {
|
||||
html: string;
|
||||
text: string;
|
||||
hasTemplate: boolean;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class TemplateProcessorService {
|
||||
private readonly logger = new Logger(TemplateProcessorService.name);
|
||||
|
||||
constructor(private readonly templatesService: TemplatesService) {}
|
||||
|
||||
/**
|
||||
* Process email content through business template
|
||||
*/
|
||||
async processEmailWithTemplate(
|
||||
businessId: string,
|
||||
emailContent: { text?: string; html?: string; subject?: string },
|
||||
// userId?: string,
|
||||
): Promise<ProcessedTemplateResult> {
|
||||
try {
|
||||
this.logger.log(`Processing email with template for business: ${businessId}`);
|
||||
|
||||
// Get business templates
|
||||
const templates = await this.templatesService.getTemplatesByBusinessId(businessId);
|
||||
|
||||
if (!templates || templates.length === 0) {
|
||||
this.logger.log(`No templates found for business: ${businessId}, using original content`);
|
||||
return {
|
||||
html: emailContent.html || this.convertTextToHtml(emailContent.text || ""),
|
||||
text: emailContent.text || this.stripHtmlTags(emailContent.html || ""),
|
||||
hasTemplate: false,
|
||||
};
|
||||
}
|
||||
|
||||
// Use the first template
|
||||
const template = templates[0];
|
||||
|
||||
this.logger.log(`Using template: ${template.name} for email processing`);
|
||||
|
||||
// Process the template with email content
|
||||
const processedContent = await this.injectContentIntoTemplate(emailContent, template.rawHtml);
|
||||
|
||||
return {
|
||||
html: processedContent.html,
|
||||
text: processedContent.text,
|
||||
hasTemplate: true,
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to process email with template for business ${businessId}:`, error);
|
||||
|
||||
// Fallback to original content if template processing fails
|
||||
return {
|
||||
html: emailContent.html || this.convertTextToHtml(emailContent.text || ""),
|
||||
text: emailContent.text || this.stripHtmlTags(emailContent.html || ""),
|
||||
hasTemplate: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject email content into template structure
|
||||
*/
|
||||
private async injectContentIntoTemplate(
|
||||
// templateStructure: Record<string, unknown>,
|
||||
emailContent: { text?: string; html?: string; subject?: string },
|
||||
rawHtml?: string,
|
||||
): Promise<{ html: string; text: string }> {
|
||||
try {
|
||||
// If template has raw HTML, use it as base and inject content
|
||||
if (rawHtml) {
|
||||
const html = this.injectContentIntoRawHtml(rawHtml, emailContent);
|
||||
return {
|
||||
html,
|
||||
text: this.stripHtmlTags(html),
|
||||
};
|
||||
}
|
||||
|
||||
// Otherwise, build simple HTML with email content
|
||||
const html = this.buildSimpleTemplate(emailContent);
|
||||
return {
|
||||
html,
|
||||
text: this.stripHtmlTags(html),
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error("Failed to inject content into template:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject email content into raw HTML template
|
||||
*/
|
||||
private injectContentIntoRawHtml(rawHtml: string, emailContent: { text?: string; html?: string; subject?: string }): string {
|
||||
let processedHtml = rawHtml;
|
||||
|
||||
// Replace placeholders with actual content
|
||||
const contentToInject = emailContent.html || this.convertTextToHtml(emailContent.text || "");
|
||||
|
||||
// Common placeholder patterns
|
||||
const placeholders = [/\{\{content\}\}/gi, /\{\{message\}\}/gi, /\{\{body\}\}/gi, /\{content\}/gi, /\{message\}/gi, /\{body\}/gi];
|
||||
|
||||
placeholders.forEach((placeholder) => {
|
||||
processedHtml = processedHtml.replace(placeholder, contentToInject);
|
||||
});
|
||||
|
||||
// Replace subject placeholders
|
||||
if (emailContent.subject) {
|
||||
const subjectPlaceholders = [/\{\{subject\}\}/gi, /\{\{title\}\}/gi, /\{subject\}/gi, /\{title\}/gi];
|
||||
|
||||
subjectPlaceholders.forEach((placeholder) => {
|
||||
processedHtml = processedHtml.replace(placeholder, emailContent.subject!);
|
||||
});
|
||||
}
|
||||
|
||||
return processedHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build simple HTML template
|
||||
*/
|
||||
private buildSimpleTemplate(emailContent: { text?: string; html?: string; subject?: string }): string {
|
||||
const content = emailContent.html || this.convertTextToHtml(emailContent.text || "");
|
||||
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>${emailContent.subject || "Email"}</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; line-height: 1.6; }
|
||||
.email-container { max-width: 600px; margin: 0 auto; }
|
||||
.content { padding: 20px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="email-container">
|
||||
<div class="content">
|
||||
${content}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert plain text to HTML
|
||||
*/
|
||||
private convertTextToHtml(text: string): string {
|
||||
return text
|
||||
.replace(/\n\n/g, "</p><p>")
|
||||
.replace(/\n/g, "<br>")
|
||||
.replace(/^(.*)$/, "<p>$1</p>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip HTML tags from content
|
||||
*/
|
||||
private stripHtmlTags(html: string): string {
|
||||
return html
|
||||
.replace(/<[^>]*>/g, "")
|
||||
.replace(/ /g, " ")
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, '"')
|
||||
.trim();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user