|
| 1 | +export interface RecipientEmailOptions { |
| 2 | + to: string; |
| 3 | + cc?: string[] | undefined; |
| 4 | + bcc?: string[] | undefined; |
| 5 | +} |
| 6 | + |
| 7 | +export interface IGenericTemplate<T> { |
| 8 | + template: string; |
| 9 | + subject: string; |
| 10 | + requiredParams: T[]; |
| 11 | + bcc?: string[]; |
| 12 | +} |
| 13 | + |
| 14 | +export default class GenericTemplate<T extends string> |
| 15 | + implements IGenericTemplate<T> |
| 16 | +{ |
| 17 | + readonly template: string; |
| 18 | + readonly subject: string; |
| 19 | + readonly requiredParams: T[]; |
| 20 | + bcc?: string[]; |
| 21 | + |
| 22 | + /** |
| 23 | + * |
| 24 | + * @param {string} template Email Template |
| 25 | + * @param {string} subject Email Subject |
| 26 | + * @param {T[]} requiredParams Required parameters for template |
| 27 | + */ |
| 28 | + constructor(template: string, subject: string, requiredParams: T[]) { |
| 29 | + this.template = template; |
| 30 | + this.subject = subject; |
| 31 | + this.requiredParams = requiredParams; |
| 32 | + } |
| 33 | + |
| 34 | + get config() { |
| 35 | + return { |
| 36 | + subject: this.subject, |
| 37 | + from: process.env["EMAIL_FROM"] as string, |
| 38 | + bcc: this.bcc, |
| 39 | + }; |
| 40 | + } |
| 41 | + |
| 42 | + /** |
| 43 | + * @param {{[x: string]: string}} params Values to replace placeholders in template text. |
| 44 | + */ |
| 45 | + validate(params: Record<T, string>) { |
| 46 | + const missing = []; |
| 47 | + for (const opt of this.requiredParams) { |
| 48 | + if (Object.prototype.hasOwnProperty.call(params, opt)) { |
| 49 | + // check to makesure the option is not empty |
| 50 | + if (params[opt] === "") { |
| 51 | + missing.push(opt); |
| 52 | + } |
| 53 | + } else { |
| 54 | + // if the option is complete missing, add it to the list |
| 55 | + missing.push(opt); |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + if (missing.length) { |
| 60 | + throw new Error(`Missing template parameters: ${missing.join(", ")}`); |
| 61 | + } else { |
| 62 | + return true; |
| 63 | + } |
| 64 | + } |
| 65 | + |
| 66 | + html(options: Record<T, string>) { |
| 67 | + return new Promise<string>((resolve, reject) => { |
| 68 | + try { |
| 69 | + this.validate(options); |
| 70 | + const content = this.template.replace( |
| 71 | + /{(\w*)}/g, |
| 72 | + function replacer(m, key: T) { |
| 73 | + if (Object.prototype.hasOwnProperty.call(options, key)) { |
| 74 | + return options[key]; |
| 75 | + } else { |
| 76 | + throw new Error(`Missing parameter: ${key}`); |
| 77 | + } |
| 78 | + }, |
| 79 | + ); |
| 80 | + resolve(this.wrapperHTML({ content })); |
| 81 | + } catch (e) { |
| 82 | + reject(e); |
| 83 | + } |
| 84 | + }); |
| 85 | + } |
| 86 | + |
| 87 | + /** |
| 88 | + * Wrapper HTML |
| 89 | + * @param {Object} Options |
| 90 | + * @param {string} Options.content |
| 91 | + * @returns |
| 92 | + */ |
| 93 | + private wrapperHTML({ content }: { content: string }) { |
| 94 | + return `<body |
| 95 | + style="background: #f3f4f6; padding: 2em; font-size:16px; font-family:source-sans-pro, Roboto, sans-serif;" |
| 96 | +> |
| 97 | + <div style=" text-align: center;"> |
| 98 | + <div |
| 99 | + style="background: white; padding: 2em; border-radius: 0.5em; max-width: 500px; text-align: left; margin: auto;" |
| 100 | + > |
| 101 | + ${content} |
| 102 | +
|
| 103 | + Best, |
| 104 | + Your Codr Team |
| 105 | + support@codrjs.com |
| 106 | + </div> |
| 107 | + </div> |
| 108 | +</body>`.replace(/[\n]*/g, ""); |
| 109 | + } |
| 110 | +} |
| 111 | + |
| 112 | +/** |
| 113 | + * Email header image code |
| 114 | + * |
| 115 | + * <img |
| 116 | + * src="cid:logo" |
| 117 | + * alt="TrustedRentr Logo" |
| 118 | + * style="display: block; width: 100%; height: 48px; margin-bottom: 2em; object-fit: contain;" |
| 119 | + * /> |
| 120 | + */ |
0 commit comments