116 lines
3.5 KiB
JavaScript
116 lines
3.5 KiB
JavaScript
/**
|
|
* Email utility functions shared across all email services
|
|
*/
|
|
|
|
/**
|
|
* Convert HTML to plain text for email fallback
|
|
* Strips HTML tags and formats content for plain text email clients
|
|
* @param {string} html - HTML content to convert
|
|
* @returns {string} Plain text version of the HTML
|
|
*/
|
|
function htmlToPlainText(html) {
|
|
return (
|
|
html
|
|
// Remove style and script tags and their content
|
|
.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "")
|
|
.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "")
|
|
// Convert common HTML elements to text equivalents
|
|
.replace(/<br\s*\/?>/gi, "\n")
|
|
.replace(/<\/p>/gi, "\n\n")
|
|
.replace(/<\/div>/gi, "\n")
|
|
.replace(/<\/li>/gi, "\n")
|
|
.replace(/<\/h[1-6]>/gi, "\n\n")
|
|
.replace(/<li>/gi, "• ")
|
|
// Remove remaining HTML tags
|
|
.replace(/<[^>]+>/g, "")
|
|
// Decode HTML entities
|
|
.replace(/ /g, " ")
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, "'")
|
|
// Remove emojis and special characters that don't render well in plain text
|
|
.replace(/[\u{1F600}-\u{1F64F}]/gu, "") // Emoticons
|
|
.replace(/[\u{1F300}-\u{1F5FF}]/gu, "") // Misc Symbols and Pictographs
|
|
.replace(/[\u{1F680}-\u{1F6FF}]/gu, "") // Transport and Map
|
|
.replace(/[\u{2600}-\u{26FF}]/gu, "") // Misc symbols
|
|
.replace(/[\u{2700}-\u{27BF}]/gu, "") // Dingbats
|
|
.replace(/[\u{FE00}-\u{FE0F}]/gu, "") // Variation Selectors
|
|
.replace(/[\u{1F900}-\u{1F9FF}]/gu, "") // Supplemental Symbols and Pictographs
|
|
.replace(/[\u{1FA70}-\u{1FAFF}]/gu, "") // Symbols and Pictographs Extended-A
|
|
// Clean up excessive whitespace
|
|
.replace(/\n\s*\n\s*\n/g, "\n\n")
|
|
.trim()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Format a date consistently for email display
|
|
* @param {Date|string} date - Date to format
|
|
* @returns {string} Formatted date string
|
|
*/
|
|
function formatEmailDate(date) {
|
|
const dateObj = typeof date === "string" ? new Date(date) : date;
|
|
return dateObj.toLocaleString("en-US", {
|
|
weekday: "long",
|
|
year: "numeric",
|
|
month: "long",
|
|
day: "numeric",
|
|
hour: "numeric",
|
|
minute: "2-digit",
|
|
hour12: true,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Format a date as a short date (no time)
|
|
* @param {Date|string} date - Date to format
|
|
* @returns {string} Formatted date string
|
|
*/
|
|
function formatShortDate(date) {
|
|
const dateObj = typeof date === "string" ? new Date(date) : date;
|
|
return dateObj.toLocaleString("en-US", {
|
|
year: "numeric",
|
|
month: "long",
|
|
day: "numeric",
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Format currency for email display
|
|
* @param {number} amount - Amount in cents or smallest currency unit
|
|
* @param {string} currency - Currency code (default: USD)
|
|
* @returns {string} Formatted currency string
|
|
*/
|
|
function formatCurrency(amount, currency = "USD") {
|
|
return new Intl.NumberFormat("en-US", {
|
|
style: "currency",
|
|
currency: currency,
|
|
}).format(amount / 100);
|
|
}
|
|
|
|
/**
|
|
* Escape HTML special characters to prevent XSS attacks
|
|
* Converts characters that could be interpreted as HTML into safe entities
|
|
* @param {*} str - Value to escape (will be converted to string)
|
|
* @returns {string} HTML-escaped string safe for insertion into HTML
|
|
*/
|
|
function escapeHtml(str) {
|
|
if (str === null || str === undefined) return "";
|
|
return String(str)
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """)
|
|
.replace(/'/g, "'");
|
|
}
|
|
|
|
module.exports = {
|
|
htmlToPlainText,
|
|
formatEmailDate,
|
|
formatShortDate,
|
|
formatCurrency,
|
|
escapeHtml,
|
|
};
|