@heliyos/heliyos-api-core 1.0.61 → 1.0.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41,11 +41,52 @@ exports.emailTemplates = {
41
41
  notificationDailySummary: "notification-daily-summary.html",
42
42
  organizationDailySummary: "organization-daily-summary.html",
43
43
  };
44
+ /**
45
+ * Simple markdown to HTML converter for email templates
46
+ */
47
+ const markdownToHtml = (text) => {
48
+ if (!text || typeof text !== "string")
49
+ return text;
50
+ return text
51
+ // Bold: **text** or __text__
52
+ .replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
53
+ .replace(/__(.*?)__/g, "<strong>$1</strong>")
54
+ // Italics: *text* or _text_
55
+ .replace(/\*(.*?)\*/g, "<em>$1</em>")
56
+ .replace(/_(.*?)_/g, "<em>$1</em>")
57
+ // Newlines to <br>
58
+ .replace(/\n/g, "<br>");
59
+ };
60
+ /**
61
+ * Recursively process object values to convert markdown to HTML
62
+ */
63
+ const processMarkdownData = (data) => {
64
+ if (!data)
65
+ return data;
66
+ if (typeof data === "string") {
67
+ return markdownToHtml(data);
68
+ }
69
+ if (Array.isArray(data)) {
70
+ return data.map((item) => processMarkdownData(item));
71
+ }
72
+ if (typeof data === "object") {
73
+ const processed = {};
74
+ for (const key in data) {
75
+ if (Object.prototype.hasOwnProperty.call(data, key)) {
76
+ processed[key] = processMarkdownData(data[key]);
77
+ }
78
+ }
79
+ return processed;
80
+ }
81
+ return data;
82
+ };
44
83
  const getEmailTemplate = (template, data) => {
45
84
  const filePath = path.join(__dirname, template);
46
85
  const htmlContent = fs.readFileSync(filePath, "utf8");
86
+ // Process data to convert markdown to HTML in strings
87
+ const processedData = processMarkdownData(data);
47
88
  const handlebarsTemplate = handlebars_1.default.compile(htmlContent);
48
- const result = handlebarsTemplate(Object.assign(Object.assign({}, data), { year: new Date().getFullYear(), company_name: "Heliyos AI" }));
89
+ const result = handlebarsTemplate(Object.assign(Object.assign({}, processedData), { year: new Date().getFullYear(), company_name: "Heliyos AI" }));
49
90
  return result;
50
91
  };
51
92
  exports.getEmailTemplate = getEmailTemplate;
@@ -69,9 +69,6 @@
69
69
  }
70
70
 
71
71
  .section-header {
72
- display: flex;
73
- justify-content: space-between;
74
- align-items: center;
75
72
  margin-bottom: 12px;
76
73
  padding-bottom: 8px;
77
74
  border-bottom: 1px solid #e5e7eb;
@@ -82,6 +79,7 @@
82
79
  font-weight: bold;
83
80
  color: #111827;
84
81
  margin: 0;
82
+ line-height: 1;
85
83
  }
86
84
 
87
85
  .section-count {
@@ -151,10 +149,6 @@
151
149
  color: #374151;
152
150
  }
153
151
 
154
- .item-link {
155
- margin-top: 10px;
156
- }
157
-
158
152
  .org-summary-box {
159
153
  background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%);
160
154
  color: #ffffff;
@@ -168,39 +162,6 @@
168
162
  font-size: 18px;
169
163
  }
170
164
 
171
- .org-summary-box p {
172
- margin: 8px 0;
173
- line-height: 1.6;
174
- }
175
-
176
- .button {
177
- display: inline-block;
178
- padding: 10px 20px;
179
- background-color: #7c3aed;
180
- color: #ffffff !important;
181
- text-decoration: none;
182
- border-radius: 6px;
183
- font-weight: bold;
184
- font-size: 13px;
185
- margin-top: 8px;
186
- }
187
-
188
- .button:hover {
189
- background-color: #6d28d9;
190
- }
191
-
192
- .view-all-link {
193
- text-align: right;
194
- margin-top: 12px;
195
- }
196
-
197
- .view-all-link a {
198
- color: #7c3aed;
199
- text-decoration: none;
200
- font-weight: bold;
201
- font-size: 14px;
202
- }
203
-
204
165
  .footer {
205
166
  background-color: #7c3aed;
206
167
  padding: 20px;
@@ -237,16 +198,26 @@
237
198
 
238
199
  {{#if has_org_summary}}
239
200
  <div class="org-summary-box">
240
- <h3>📊 Organization Summary</h3>
241
- <p>{{org_summary}}</p>
201
+ <table border="0" cellpadding="0" cellspacing="0">
202
+ <tr>
203
+ <td style="vertical-align: middle; padding-right: 8px; font-size: 20px;">📊</td>
204
+ <td style="vertical-align: middle;"><h3 style="margin: 0;">Organization Summary</h3></td>
205
+ </tr>
206
+ </table>
207
+ <p style="margin-top: 12px; line-height: 1.6;">{{{org_summary}}}</p>
242
208
  </div>
243
209
  {{/if}}
244
210
 
245
211
  {{#if has_tasks}}
246
212
  <div class="section">
247
213
  <div class="section-header">
248
- <h2 class="section-title">✅ Tasks</h2>
249
- <span class="section-count">{{tasks_count}}</span>
214
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
215
+ <tr>
216
+ <td style="vertical-align: middle; padding-right: 8px; width: 24px; font-size: 20px;">✓</td>
217
+ <td style="vertical-align: middle;"><h2 class="section-title">Tasks</h2></td>
218
+ <td style="vertical-align: middle; text-align: right;"><span class="section-count">{{tasks_count}}</span></td>
219
+ </tr>
220
+ </table>
250
221
  </div>
251
222
  <div class="section-content">
252
223
  {{#each tasks}}
@@ -292,8 +263,13 @@
292
263
  {{#if has_deals}}
293
264
  <div class="section">
294
265
  <div class="section-header">
295
- <h2 class="section-title">💰 Deals</h2>
296
- <span class="section-count">{{deals_count}}</span>
266
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
267
+ <tr>
268
+ <td style="vertical-align: middle; padding-right: 8px; width: 24px; font-size: 20px;">💰</td>
269
+ <td style="vertical-align: middle;"><h2 class="section-title">Deals</h2></td>
270
+ <td style="vertical-align: middle; text-align: right;"><span class="section-count">{{deals_count}}</span></td>
271
+ </tr>
272
+ </table>
297
273
  </div>
298
274
  <div class="section-content">
299
275
  {{#each deals}}
@@ -339,8 +315,13 @@
339
315
  {{#if has_approvals}}
340
316
  <div class="section">
341
317
  <div class="section-header">
342
- <h2 class="section-title">✔️ Approvals</h2>
343
- <span class="section-count">{{approvals_count}}</span>
318
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
319
+ <tr>
320
+ <td style="vertical-align: middle; padding-right: 8px; width: 24px; font-size: 20px;">✔️</td>
321
+ <td style="vertical-align: middle;"><h2 class="section-title">Reviews</h2></td>
322
+ <td style="vertical-align: middle; text-align: right;"><span class="section-count">{{approvals_count}}</span></td>
323
+ </tr>
324
+ </table>
344
325
  </div>
345
326
  <div class="section-content">
346
327
  {{#each approvals}}
@@ -386,8 +367,13 @@
386
367
  {{#if has_leadsets}}
387
368
  <div class="section">
388
369
  <div class="section-header">
389
- <h2 class="section-title">📋 Leadsets</h2>
390
- <span class="section-count">{{leadsets_count}}</span>
370
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
371
+ <tr>
372
+ <td style="vertical-align: middle; padding-right: 8px; width: 24px; font-size: 20px;">✨</td>
373
+ <td style="vertical-align: middle;"><h2 class="section-title">Leadsets</h2></td>
374
+ <td style="vertical-align: middle; text-align: right;"><span class="section-count">{{leadsets_count}}</span></td>
375
+ </tr>
376
+ </table>
391
377
  </div>
392
378
  <div class="section-content">
393
379
  {{#each leadsets}}
@@ -156,7 +156,7 @@
156
156
 
157
157
  <div class="event-card">
158
158
  <div class="event-badge">{{event_type_label}}</div>
159
- <div class="event-title">{{object_name}}</div>
159
+ <div class="event-title">{{{object_name}}}</div>
160
160
  {{#if details}}
161
161
  <div class="event-details">
162
162
  <table class="detail-table">
@@ -164,7 +164,7 @@
164
164
  {{#each details}}
165
165
  <td class="detail-cell">
166
166
  <div class="detail-label">{{this.label}}</div>
167
- <div class="detail-value">{{this.value}}</div>
167
+ <div class="detail-value">{{{this.value}}}</div>
168
168
  </td>
169
169
  {{/each}}
170
170
  </tr>
@@ -1,244 +1,200 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
+
3
4
  <head>
4
5
  <meta charset="UTF-8">
5
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
7
  <title>{{organization_name}} Daily Briefing</title>
7
8
  <style>
8
9
  body {
10
+ font-family: Arial, sans-serif;
11
+ line-height: 1.6;
12
+ color: #0e0d0c;
13
+ background-color: #f8f8f6;
9
14
  margin: 0;
10
15
  padding: 0;
11
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
12
- background-color: #f5f5f7;
13
- -webkit-font-smoothing: antialiased;
14
- -moz-osx-font-smoothing: grayscale;
15
16
  }
16
- .email-container {
17
- max-width: 680px;
18
- margin: 40px auto;
17
+
18
+ .container {
19
+ max-width: 600px;
20
+ margin: 20px auto;
19
21
  background-color: #ffffff;
20
- border-radius: 16px;
22
+ border: 2px solid #7c3aed;
23
+ border-radius: 12px;
21
24
  overflow: hidden;
22
- box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
23
25
  }
26
+
24
27
  .header {
25
- background: linear-gradient(135deg, #8b5cf6 0%, #6d28d9 100%);
26
- padding: 48px 40px;
28
+ background-color: #7c3aed;
29
+ padding: 30px 20px;
27
30
  text-align: center;
28
31
  }
29
- .logo {
30
- display: flex;
31
- align-items: center;
32
- justify-content: center;
33
- gap: 12px;
34
- margin-bottom: 24px;
35
- }
36
- .logo-icon {
37
- width: 40px;
38
- height: 40px;
39
- background-color: #1e1b29;
40
- border-radius: 50%;
41
- display: flex;
42
- align-items: center;
43
- justify-content: center;
44
- }
45
- .logo-text {
46
- font-size: 28px;
47
- font-weight: 600;
48
- color: #ffffff;
49
- letter-spacing: -0.5px;
32
+
33
+ .header img {
34
+ max-width: 180px;
35
+ height: auto;
36
+ margin-bottom: 12px;
50
37
  }
51
- .header h1 {
52
- margin: 0 0 12px 0;
53
- font-size: 32px;
54
- font-weight: 700;
38
+
39
+ .header-title {
55
40
  color: #ffffff;
56
- letter-spacing: -0.5px;
57
- line-height: 1.2;
41
+ font-size: 24px;
42
+ font-weight: bold;
43
+ margin: 10px 0 4px 0;
58
44
  }
45
+
59
46
  .header-date {
60
- font-size: 16px;
61
- color: rgba(255, 255, 255, 0.9);
62
- font-weight: 500;
47
+ color: #ffffff;
48
+ opacity: 0.9;
49
+ font-size: 14px;
63
50
  }
51
+
64
52
  .badge {
65
53
  display: inline-block;
66
- padding: 8px 16px;
67
- background-color: rgba(255, 255, 255, 0.15);
54
+ padding: 6px 14px;
55
+ background-color: rgba(255, 255, 255, 0.2);
68
56
  border-radius: 20px;
69
- font-size: 14px;
57
+ margin-top: 10px;
58
+ }
59
+
60
+ .badge-text {
61
+ font-size: 13px;
70
62
  color: #ffffff;
71
63
  font-weight: 600;
72
- margin-top: 16px;
73
- backdrop-filter: blur(10px);
64
+ line-height: 1;
74
65
  }
66
+
75
67
  .content {
76
- padding: 48px 40px;
68
+ padding: 30px;
69
+ background-color: #ffffff;
77
70
  }
71
+
78
72
  .greeting {
79
- font-size: 18px;
80
- line-height: 1.6;
81
- color: #1f2937;
82
- margin-bottom: 32px;
83
- }
84
- .greeting strong {
85
- color: #111827;
73
+ font-size: 16px;
74
+ color: #0e0d0c;
75
+ margin-bottom: 20px;
86
76
  }
77
+
87
78
  .section {
88
- margin-bottom: 40px;
79
+ margin: 20px 0;
80
+ padding: 0;
81
+ background-color: transparent;
82
+ border-radius: 0;
83
+ border-left: none;
89
84
  }
85
+
86
+ .section-header {
87
+ margin-bottom: 12px;
88
+ padding-bottom: 8px;
89
+ border-bottom: 1px solid #e5e7eb;
90
+ }
91
+
90
92
  .section-title {
91
- display: flex;
92
- align-items: center;
93
- gap: 10px;
94
- font-size: 20px;
95
- font-weight: 700;
93
+ font-size: 16px;
94
+ font-weight: bold;
96
95
  color: #111827;
97
- margin-bottom: 20px;
98
- padding-bottom: 12px;
99
- border-bottom: 2px solid #e5e7eb;
100
- }
101
- .section-icon {
102
- font-size: 24px;
96
+ margin: 0;
97
+ line-height: 1;
103
98
  }
99
+
104
100
  .summary-text {
105
- font-size: 16px;
106
- line-height: 1.8;
101
+ font-size: 15px;
102
+ line-height: 1.7;
107
103
  color: #374151;
108
- padding: 20px;
104
+ padding: 16px;
109
105
  background-color: #f9fafb;
110
- border-radius: 12px;
111
- border-left: 4px solid #8b5cf6;
112
- white-space: pre-wrap;
106
+ border-radius: 8px;
107
+ border-left: 4px solid #7c3aed;
108
+ margin-bottom: 20px;
113
109
  word-wrap: break-word;
114
110
  }
111
+
115
112
  .list-container {
116
113
  background-color: #ffffff;
117
114
  }
115
+
118
116
  .list-item {
119
- padding: 16px 0;
117
+ padding: 12px 0;
120
118
  border-bottom: 1px solid #f3f4f6;
121
- line-height: 1.7;
119
+ line-height: 1.6;
122
120
  color: #374151;
123
- font-size: 15px;
124
- display: flex;
125
- gap: 12px;
121
+ font-size: 14px;
126
122
  }
123
+
127
124
  .list-item:last-child {
128
125
  border-bottom: none;
129
126
  }
130
- .list-item-icon {
131
- flex-shrink: 0;
132
- margin-top: 2px;
133
- }
134
- .list-item-text {
135
- flex: 1;
136
- }
137
- .footer-notice {
138
- text-align: center;
139
- padding: 32px 40px;
140
- background-color: #f9fafb;
141
- border-top: 1px solid #e5e7eb;
142
- }
143
- .footer-notice p {
144
- margin: 8px 0;
145
- font-size: 14px;
146
- color: #6b7280;
147
- line-height: 1.6;
148
- }
149
- .footer-notice a {
150
- color: #8b5cf6;
151
- text-decoration: none;
152
- font-weight: 600;
153
- }
154
- .footer-notice a:hover {
155
- text-decoration: underline;
156
- }
127
+
157
128
  .footer {
129
+ background-color: #7c3aed;
130
+ padding: 20px;
158
131
  text-align: center;
159
- padding: 32px 40px;
160
- background-color: #8b5cf6;
161
- color: rgba(255, 255, 255, 0.8);
162
- }
163
- .footer p {
164
- margin: 8px 0;
165
- font-size: 13px;
166
- line-height: 1.6;
167
- }
168
- .footer-links {
169
- margin-top: 16px;
132
+ font-size: 12px;
133
+ color: #ffffff;
170
134
  }
171
- .footer-links a {
135
+
136
+ .footer a {
172
137
  color: #ffffff;
173
138
  text-decoration: none;
174
- margin: 0 8px;
175
- font-weight: 500;
176
139
  }
177
- @media only screen and (max-width: 640px) {
178
- .email-container {
179
- margin: 0;
180
- border-radius: 0;
181
- }
182
- .header {
183
- padding: 32px 24px;
184
- }
185
- .header h1 {
186
- font-size: 26px;
187
- }
188
- .content {
189
- padding: 32px 24px;
190
- }
191
- .footer-notice,
192
- .footer {
193
- padding: 24px 24px;
194
- }
140
+
141
+ .divider {
142
+ height: 1px;
143
+ background-color: #ebe7db;
144
+ margin: 24px 0;
195
145
  }
196
146
  </style>
197
147
  </head>
148
+
198
149
  <body>
199
- <div class="email-container">
150
+ <div class="container">
200
151
  <div class="header">
201
- <div class="logo">
202
- <div class="logo-icon">
203
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
204
- <circle cx="12" cy="12" r="10" fill="white"/>
205
- <circle cx="12" cy="12" r="4" fill="#8b5cf6"/>
206
- </svg>
207
- </div>
208
- <div class="logo-text">heliyos</div>
209
- </div>
210
- <h1>{{organization_name}} Daily Briefing</h1>
152
+ <img src="https://assets.heliyos.ai/heliyos-logo-white.png" alt="Heliyos AI">
153
+ <div class="header-title">{{organization_name}} Daily Briefing</div>
211
154
  <div class="header-date">{{date}}</div>
212
- <div class="badge">📊 Organization summary</div>
155
+ <div class="badge">
156
+ <table border="0" cellpadding="0" cellspacing="0" style="margin: 0 auto;">
157
+ <tr>
158
+ <td style="vertical-align: middle; padding-right: 5px; font-size: 14px;">📊</td>
159
+ <td style="vertical-align: middle;" class="badge-text">Organization summary</td>
160
+ </tr>
161
+ </table>
162
+ </div>
213
163
  </div>
214
164
 
215
165
  <div class="content">
216
166
  <div class="greeting">
217
- <strong>Hello {{first_name}},</strong><br>
167
+ Hello {{first_name}},<br>
218
168
  Here's your comprehensive daily briefing for {{organization_name}}.
219
169
  </div>
220
170
 
221
171
  <!-- Summary Section -->
222
172
  <div class="section">
223
- <div class="section-title">
224
- <span class="section-icon">📋</span>
225
- <span>Daily Overview</span>
173
+ <div class="section-header">
174
+ <table border="0" cellpadding="0" cellspacing="0">
175
+ <tr>
176
+ <td style="vertical-align: middle; padding-right: 8px; font-size: 20px;">📋</td>
177
+ <td style="vertical-align: middle;"><h2 class="section-title">Daily Overview</h2></td>
178
+ </tr>
179
+ </table>
226
180
  </div>
227
- <div class="summary-text">{{summary}}</div>
181
+ <div class="summary-text">{{{summary}}}</div>
228
182
  </div>
229
183
 
230
184
  <!-- Key Highlights -->
231
185
  {{#if key_highlights}}
232
186
  <div class="section">
233
- <div class="section-title">
234
- <span class="section-icon">✨</span>
235
- <span>Key Highlights</span>
187
+ <div class="section-header">
188
+ <table border="0" cellpadding="0" cellspacing="0">
189
+ <tr>
190
+ <td style="vertical-align: middle; padding-right: 8px; font-size: 20px;">✨</td>
191
+ <td style="vertical-align: middle;"><h2 class="section-title">Key Highlights</h2></td>
192
+ </tr>
193
+ </table>
236
194
  </div>
237
195
  <div class="list-container">
238
196
  {{#each key_highlights}}
239
- <div class="list-item">
240
- <div class="list-item-text">{{this}}</div>
241
- </div>
197
+ <div class="list-item">{{{this}}}</div>
242
198
  {{/each}}
243
199
  </div>
244
200
  </div>
@@ -247,15 +203,17 @@
247
203
  <!-- Action Items -->
248
204
  {{#if action_items}}
249
205
  <div class="section">
250
- <div class="section-title">
251
- <span class="section-icon">📋</span>
252
- <span>Action Items</span>
206
+ <div class="section-header">
207
+ <table border="0" cellpadding="0" cellspacing="0">
208
+ <tr>
209
+ <td style="vertical-align: middle; padding-right: 8px; font-size: 20px;">✓</td>
210
+ <td style="vertical-align: middle;"><h2 class="section-title">Action Items</h2></td>
211
+ </tr>
212
+ </table>
253
213
  </div>
254
214
  <div class="list-container">
255
215
  {{#each action_items}}
256
- <div class="list-item">
257
- <div class="list-item-text">{{this}}</div>
258
- </div>
216
+ <div class="list-item">{{{this}}}</div>
259
217
  {{/each}}
260
218
  </div>
261
219
  </div>
@@ -264,33 +222,37 @@
264
222
  <!-- Upcoming Priorities -->
265
223
  {{#if upcoming_priorities}}
266
224
  <div class="section">
267
- <div class="section-title">
268
- <span class="section-icon">🎯</span>
269
- <span>Upcoming Priorities</span>
225
+ <div class="section-header">
226
+ <table border="0" cellpadding="0" cellspacing="0">
227
+ <tr>
228
+ <td style="vertical-align: middle; padding-right: 8px; font-size: 20px;">🎯</td>
229
+ <td style="vertical-align: middle;"><h2 class="section-title">Upcoming Priorities</h2></td>
230
+ </tr>
231
+ </table>
270
232
  </div>
271
233
  <div class="list-container">
272
234
  {{#each upcoming_priorities}}
273
- <div class="list-item">
274
- <div class="list-item-text">{{this}}</div>
275
- </div>
235
+ <div class="list-item">{{{this}}}</div>
276
236
  {{/each}}
277
237
  </div>
278
238
  </div>
279
239
  {{/if}}
280
- </div>
281
240
 
282
- <div class="footer-notice">
283
- <p>You received this email because you have daily organization summaries enabled.</p>
284
- <p><a href="{{settings_url}}">Manage your notification preferences</a></p>
285
- </div>
241
+ <div class="divider"></div>
286
242
 
243
+ <p style="text-align: center; color: #5c5545; font-size: 14px;">
244
+ You received this email because you have daily organization summaries enabled.<br>
245
+ <a href="{{settings_url}}" style="color: #7c3aed;">Manage your notification preferences</a>
246
+ </p>
247
+ </div>
287
248
  <div class="footer">
288
- <p>&copy; {{year}} Heliyos AI. All rights reserved.</p>
289
- <div class="footer-links">
249
+ <p {{year}} {{company_name}}. All rights reserved.</p>
250
+ <p>
290
251
  <a href="{{settings_url}}">Notification Settings</a> |
291
- <span>This is an automated message, please do not reply.</span>
292
- </div>
252
+ This is an automated message, please do not reply.
253
+ </p>
293
254
  </div>
294
255
  </div>
295
256
  </body>
257
+
296
258
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heliyos/heliyos-api-core",
3
- "version": "1.0.61",
3
+ "version": "1.0.63",
4
4
  "description": "Heliyos's core api functions and middlewares. Its a private package hosted on npm.",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -14,13 +14,60 @@ export const emailTemplates = {
14
14
  organizationDailySummary: "organization-daily-summary.html",
15
15
  };
16
16
 
17
+ /**
18
+ * Simple markdown to HTML converter for email templates
19
+ */
20
+ const markdownToHtml = (text: string): string => {
21
+ if (!text || typeof text !== "string") return text;
22
+
23
+ return text
24
+ // Bold: **text** or __text__
25
+ .replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
26
+ .replace(/__(.*?)__/g, "<strong>$1</strong>")
27
+ // Italics: *text* or _text_
28
+ .replace(/\*(.*?)\*/g, "<em>$1</em>")
29
+ .replace(/_(.*?)_/g, "<em>$1</em>")
30
+ // Newlines to <br>
31
+ .replace(/\n/g, "<br>");
32
+ };
33
+
34
+ /**
35
+ * Recursively process object values to convert markdown to HTML
36
+ */
37
+ const processMarkdownData = (data: any): any => {
38
+ if (!data) return data;
39
+
40
+ if (typeof data === "string") {
41
+ return markdownToHtml(data);
42
+ }
43
+
44
+ if (Array.isArray(data)) {
45
+ return data.map((item) => processMarkdownData(item));
46
+ }
47
+
48
+ if (typeof data === "object") {
49
+ const processed: any = {};
50
+ for (const key in data) {
51
+ if (Object.prototype.hasOwnProperty.call(data, key)) {
52
+ processed[key] = processMarkdownData(data[key]);
53
+ }
54
+ }
55
+ return processed;
56
+ }
57
+
58
+ return data;
59
+ };
60
+
17
61
  export const getEmailTemplate = (template: string, data: object) => {
18
62
  const filePath = path.join(__dirname, template);
19
63
  const htmlContent = fs.readFileSync(filePath, "utf8");
20
64
 
65
+ // Process data to convert markdown to HTML in strings
66
+ const processedData = processMarkdownData(data);
67
+
21
68
  const handlebarsTemplate = Handlebars.compile(htmlContent);
22
69
  const result = handlebarsTemplate({
23
- ...data,
70
+ ...processedData,
24
71
  year: new Date().getFullYear(),
25
72
  company_name: "Heliyos AI",
26
73
  });
@@ -69,9 +69,6 @@
69
69
  }
70
70
 
71
71
  .section-header {
72
- display: flex;
73
- justify-content: space-between;
74
- align-items: center;
75
72
  margin-bottom: 12px;
76
73
  padding-bottom: 8px;
77
74
  border-bottom: 1px solid #e5e7eb;
@@ -82,6 +79,7 @@
82
79
  font-weight: bold;
83
80
  color: #111827;
84
81
  margin: 0;
82
+ line-height: 1;
85
83
  }
86
84
 
87
85
  .section-count {
@@ -151,10 +149,6 @@
151
149
  color: #374151;
152
150
  }
153
151
 
154
- .item-link {
155
- margin-top: 10px;
156
- }
157
-
158
152
  .org-summary-box {
159
153
  background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%);
160
154
  color: #ffffff;
@@ -168,39 +162,6 @@
168
162
  font-size: 18px;
169
163
  }
170
164
 
171
- .org-summary-box p {
172
- margin: 8px 0;
173
- line-height: 1.6;
174
- }
175
-
176
- .button {
177
- display: inline-block;
178
- padding: 10px 20px;
179
- background-color: #7c3aed;
180
- color: #ffffff !important;
181
- text-decoration: none;
182
- border-radius: 6px;
183
- font-weight: bold;
184
- font-size: 13px;
185
- margin-top: 8px;
186
- }
187
-
188
- .button:hover {
189
- background-color: #6d28d9;
190
- }
191
-
192
- .view-all-link {
193
- text-align: right;
194
- margin-top: 12px;
195
- }
196
-
197
- .view-all-link a {
198
- color: #7c3aed;
199
- text-decoration: none;
200
- font-weight: bold;
201
- font-size: 14px;
202
- }
203
-
204
165
  .footer {
205
166
  background-color: #7c3aed;
206
167
  padding: 20px;
@@ -237,16 +198,26 @@
237
198
 
238
199
  {{#if has_org_summary}}
239
200
  <div class="org-summary-box">
240
- <h3>📊 Organization Summary</h3>
241
- <p>{{org_summary}}</p>
201
+ <table border="0" cellpadding="0" cellspacing="0">
202
+ <tr>
203
+ <td style="vertical-align: middle; padding-right: 8px; font-size: 20px;">📊</td>
204
+ <td style="vertical-align: middle;"><h3 style="margin: 0;">Organization Summary</h3></td>
205
+ </tr>
206
+ </table>
207
+ <p style="margin-top: 12px; line-height: 1.6;">{{{org_summary}}}</p>
242
208
  </div>
243
209
  {{/if}}
244
210
 
245
211
  {{#if has_tasks}}
246
212
  <div class="section">
247
213
  <div class="section-header">
248
- <h2 class="section-title">✅ Tasks</h2>
249
- <span class="section-count">{{tasks_count}}</span>
214
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
215
+ <tr>
216
+ <td style="vertical-align: middle; padding-right: 8px; width: 24px; font-size: 20px;">✓</td>
217
+ <td style="vertical-align: middle;"><h2 class="section-title">Tasks</h2></td>
218
+ <td style="vertical-align: middle; text-align: right;"><span class="section-count">{{tasks_count}}</span></td>
219
+ </tr>
220
+ </table>
250
221
  </div>
251
222
  <div class="section-content">
252
223
  {{#each tasks}}
@@ -292,8 +263,13 @@
292
263
  {{#if has_deals}}
293
264
  <div class="section">
294
265
  <div class="section-header">
295
- <h2 class="section-title">💰 Deals</h2>
296
- <span class="section-count">{{deals_count}}</span>
266
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
267
+ <tr>
268
+ <td style="vertical-align: middle; padding-right: 8px; width: 24px; font-size: 20px;">💰</td>
269
+ <td style="vertical-align: middle;"><h2 class="section-title">Deals</h2></td>
270
+ <td style="vertical-align: middle; text-align: right;"><span class="section-count">{{deals_count}}</span></td>
271
+ </tr>
272
+ </table>
297
273
  </div>
298
274
  <div class="section-content">
299
275
  {{#each deals}}
@@ -339,8 +315,13 @@
339
315
  {{#if has_approvals}}
340
316
  <div class="section">
341
317
  <div class="section-header">
342
- <h2 class="section-title">✔️ Approvals</h2>
343
- <span class="section-count">{{approvals_count}}</span>
318
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
319
+ <tr>
320
+ <td style="vertical-align: middle; padding-right: 8px; width: 24px; font-size: 20px;">✔️</td>
321
+ <td style="vertical-align: middle;"><h2 class="section-title">Reviews</h2></td>
322
+ <td style="vertical-align: middle; text-align: right;"><span class="section-count">{{approvals_count}}</span></td>
323
+ </tr>
324
+ </table>
344
325
  </div>
345
326
  <div class="section-content">
346
327
  {{#each approvals}}
@@ -386,8 +367,13 @@
386
367
  {{#if has_leadsets}}
387
368
  <div class="section">
388
369
  <div class="section-header">
389
- <h2 class="section-title">📋 Leadsets</h2>
390
- <span class="section-count">{{leadsets_count}}</span>
370
+ <table border="0" cellpadding="0" cellspacing="0" width="100%">
371
+ <tr>
372
+ <td style="vertical-align: middle; padding-right: 8px; width: 24px; font-size: 20px;">✨</td>
373
+ <td style="vertical-align: middle;"><h2 class="section-title">Leadsets</h2></td>
374
+ <td style="vertical-align: middle; text-align: right;"><span class="section-count">{{leadsets_count}}</span></td>
375
+ </tr>
376
+ </table>
391
377
  </div>
392
378
  <div class="section-content">
393
379
  {{#each leadsets}}
@@ -156,7 +156,7 @@
156
156
 
157
157
  <div class="event-card">
158
158
  <div class="event-badge">{{event_type_label}}</div>
159
- <div class="event-title">{{object_name}}</div>
159
+ <div class="event-title">{{{object_name}}}</div>
160
160
  {{#if details}}
161
161
  <div class="event-details">
162
162
  <table class="detail-table">
@@ -164,7 +164,7 @@
164
164
  {{#each details}}
165
165
  <td class="detail-cell">
166
166
  <div class="detail-label">{{this.label}}</div>
167
- <div class="detail-value">{{this.value}}</div>
167
+ <div class="detail-value">{{{this.value}}}</div>
168
168
  </td>
169
169
  {{/each}}
170
170
  </tr>
@@ -1,244 +1,200 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
+
3
4
  <head>
4
5
  <meta charset="UTF-8">
5
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
7
  <title>{{organization_name}} Daily Briefing</title>
7
8
  <style>
8
9
  body {
10
+ font-family: Arial, sans-serif;
11
+ line-height: 1.6;
12
+ color: #0e0d0c;
13
+ background-color: #f8f8f6;
9
14
  margin: 0;
10
15
  padding: 0;
11
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
12
- background-color: #f5f5f7;
13
- -webkit-font-smoothing: antialiased;
14
- -moz-osx-font-smoothing: grayscale;
15
16
  }
16
- .email-container {
17
- max-width: 680px;
18
- margin: 40px auto;
17
+
18
+ .container {
19
+ max-width: 600px;
20
+ margin: 20px auto;
19
21
  background-color: #ffffff;
20
- border-radius: 16px;
22
+ border: 2px solid #7c3aed;
23
+ border-radius: 12px;
21
24
  overflow: hidden;
22
- box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
23
25
  }
26
+
24
27
  .header {
25
- background: linear-gradient(135deg, #8b5cf6 0%, #6d28d9 100%);
26
- padding: 48px 40px;
28
+ background-color: #7c3aed;
29
+ padding: 30px 20px;
27
30
  text-align: center;
28
31
  }
29
- .logo {
30
- display: flex;
31
- align-items: center;
32
- justify-content: center;
33
- gap: 12px;
34
- margin-bottom: 24px;
35
- }
36
- .logo-icon {
37
- width: 40px;
38
- height: 40px;
39
- background-color: #1e1b29;
40
- border-radius: 50%;
41
- display: flex;
42
- align-items: center;
43
- justify-content: center;
44
- }
45
- .logo-text {
46
- font-size: 28px;
47
- font-weight: 600;
48
- color: #ffffff;
49
- letter-spacing: -0.5px;
32
+
33
+ .header img {
34
+ max-width: 180px;
35
+ height: auto;
36
+ margin-bottom: 12px;
50
37
  }
51
- .header h1 {
52
- margin: 0 0 12px 0;
53
- font-size: 32px;
54
- font-weight: 700;
38
+
39
+ .header-title {
55
40
  color: #ffffff;
56
- letter-spacing: -0.5px;
57
- line-height: 1.2;
41
+ font-size: 24px;
42
+ font-weight: bold;
43
+ margin: 10px 0 4px 0;
58
44
  }
45
+
59
46
  .header-date {
60
- font-size: 16px;
61
- color: rgba(255, 255, 255, 0.9);
62
- font-weight: 500;
47
+ color: #ffffff;
48
+ opacity: 0.9;
49
+ font-size: 14px;
63
50
  }
51
+
64
52
  .badge {
65
53
  display: inline-block;
66
- padding: 8px 16px;
67
- background-color: rgba(255, 255, 255, 0.15);
54
+ padding: 6px 14px;
55
+ background-color: rgba(255, 255, 255, 0.2);
68
56
  border-radius: 20px;
69
- font-size: 14px;
57
+ margin-top: 10px;
58
+ }
59
+
60
+ .badge-text {
61
+ font-size: 13px;
70
62
  color: #ffffff;
71
63
  font-weight: 600;
72
- margin-top: 16px;
73
- backdrop-filter: blur(10px);
64
+ line-height: 1;
74
65
  }
66
+
75
67
  .content {
76
- padding: 48px 40px;
68
+ padding: 30px;
69
+ background-color: #ffffff;
77
70
  }
71
+
78
72
  .greeting {
79
- font-size: 18px;
80
- line-height: 1.6;
81
- color: #1f2937;
82
- margin-bottom: 32px;
83
- }
84
- .greeting strong {
85
- color: #111827;
73
+ font-size: 16px;
74
+ color: #0e0d0c;
75
+ margin-bottom: 20px;
86
76
  }
77
+
87
78
  .section {
88
- margin-bottom: 40px;
79
+ margin: 20px 0;
80
+ padding: 0;
81
+ background-color: transparent;
82
+ border-radius: 0;
83
+ border-left: none;
89
84
  }
85
+
86
+ .section-header {
87
+ margin-bottom: 12px;
88
+ padding-bottom: 8px;
89
+ border-bottom: 1px solid #e5e7eb;
90
+ }
91
+
90
92
  .section-title {
91
- display: flex;
92
- align-items: center;
93
- gap: 10px;
94
- font-size: 20px;
95
- font-weight: 700;
93
+ font-size: 16px;
94
+ font-weight: bold;
96
95
  color: #111827;
97
- margin-bottom: 20px;
98
- padding-bottom: 12px;
99
- border-bottom: 2px solid #e5e7eb;
100
- }
101
- .section-icon {
102
- font-size: 24px;
96
+ margin: 0;
97
+ line-height: 1;
103
98
  }
99
+
104
100
  .summary-text {
105
- font-size: 16px;
106
- line-height: 1.8;
101
+ font-size: 15px;
102
+ line-height: 1.7;
107
103
  color: #374151;
108
- padding: 20px;
104
+ padding: 16px;
109
105
  background-color: #f9fafb;
110
- border-radius: 12px;
111
- border-left: 4px solid #8b5cf6;
112
- white-space: pre-wrap;
106
+ border-radius: 8px;
107
+ border-left: 4px solid #7c3aed;
108
+ margin-bottom: 20px;
113
109
  word-wrap: break-word;
114
110
  }
111
+
115
112
  .list-container {
116
113
  background-color: #ffffff;
117
114
  }
115
+
118
116
  .list-item {
119
- padding: 16px 0;
117
+ padding: 12px 0;
120
118
  border-bottom: 1px solid #f3f4f6;
121
- line-height: 1.7;
119
+ line-height: 1.6;
122
120
  color: #374151;
123
- font-size: 15px;
124
- display: flex;
125
- gap: 12px;
121
+ font-size: 14px;
126
122
  }
123
+
127
124
  .list-item:last-child {
128
125
  border-bottom: none;
129
126
  }
130
- .list-item-icon {
131
- flex-shrink: 0;
132
- margin-top: 2px;
133
- }
134
- .list-item-text {
135
- flex: 1;
136
- }
137
- .footer-notice {
138
- text-align: center;
139
- padding: 32px 40px;
140
- background-color: #f9fafb;
141
- border-top: 1px solid #e5e7eb;
142
- }
143
- .footer-notice p {
144
- margin: 8px 0;
145
- font-size: 14px;
146
- color: #6b7280;
147
- line-height: 1.6;
148
- }
149
- .footer-notice a {
150
- color: #8b5cf6;
151
- text-decoration: none;
152
- font-weight: 600;
153
- }
154
- .footer-notice a:hover {
155
- text-decoration: underline;
156
- }
127
+
157
128
  .footer {
129
+ background-color: #7c3aed;
130
+ padding: 20px;
158
131
  text-align: center;
159
- padding: 32px 40px;
160
- background-color: #8b5cf6;
161
- color: rgba(255, 255, 255, 0.8);
162
- }
163
- .footer p {
164
- margin: 8px 0;
165
- font-size: 13px;
166
- line-height: 1.6;
167
- }
168
- .footer-links {
169
- margin-top: 16px;
132
+ font-size: 12px;
133
+ color: #ffffff;
170
134
  }
171
- .footer-links a {
135
+
136
+ .footer a {
172
137
  color: #ffffff;
173
138
  text-decoration: none;
174
- margin: 0 8px;
175
- font-weight: 500;
176
139
  }
177
- @media only screen and (max-width: 640px) {
178
- .email-container {
179
- margin: 0;
180
- border-radius: 0;
181
- }
182
- .header {
183
- padding: 32px 24px;
184
- }
185
- .header h1 {
186
- font-size: 26px;
187
- }
188
- .content {
189
- padding: 32px 24px;
190
- }
191
- .footer-notice,
192
- .footer {
193
- padding: 24px 24px;
194
- }
140
+
141
+ .divider {
142
+ height: 1px;
143
+ background-color: #ebe7db;
144
+ margin: 24px 0;
195
145
  }
196
146
  </style>
197
147
  </head>
148
+
198
149
  <body>
199
- <div class="email-container">
150
+ <div class="container">
200
151
  <div class="header">
201
- <div class="logo">
202
- <div class="logo-icon">
203
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
204
- <circle cx="12" cy="12" r="10" fill="white"/>
205
- <circle cx="12" cy="12" r="4" fill="#8b5cf6"/>
206
- </svg>
207
- </div>
208
- <div class="logo-text">heliyos</div>
209
- </div>
210
- <h1>{{organization_name}} Daily Briefing</h1>
152
+ <img src="https://assets.heliyos.ai/heliyos-logo-white.png" alt="Heliyos AI">
153
+ <div class="header-title">{{organization_name}} Daily Briefing</div>
211
154
  <div class="header-date">{{date}}</div>
212
- <div class="badge">📊 Organization summary</div>
155
+ <div class="badge">
156
+ <table border="0" cellpadding="0" cellspacing="0" style="margin: 0 auto;">
157
+ <tr>
158
+ <td style="vertical-align: middle; padding-right: 5px; font-size: 14px;">📊</td>
159
+ <td style="vertical-align: middle;" class="badge-text">Organization summary</td>
160
+ </tr>
161
+ </table>
162
+ </div>
213
163
  </div>
214
164
 
215
165
  <div class="content">
216
166
  <div class="greeting">
217
- <strong>Hello {{first_name}},</strong><br>
167
+ Hello {{first_name}},<br>
218
168
  Here's your comprehensive daily briefing for {{organization_name}}.
219
169
  </div>
220
170
 
221
171
  <!-- Summary Section -->
222
172
  <div class="section">
223
- <div class="section-title">
224
- <span class="section-icon">📋</span>
225
- <span>Daily Overview</span>
173
+ <div class="section-header">
174
+ <table border="0" cellpadding="0" cellspacing="0">
175
+ <tr>
176
+ <td style="vertical-align: middle; padding-right: 8px; font-size: 20px;">📋</td>
177
+ <td style="vertical-align: middle;"><h2 class="section-title">Daily Overview</h2></td>
178
+ </tr>
179
+ </table>
226
180
  </div>
227
- <div class="summary-text">{{summary}}</div>
181
+ <div class="summary-text">{{{summary}}}</div>
228
182
  </div>
229
183
 
230
184
  <!-- Key Highlights -->
231
185
  {{#if key_highlights}}
232
186
  <div class="section">
233
- <div class="section-title">
234
- <span class="section-icon">✨</span>
235
- <span>Key Highlights</span>
187
+ <div class="section-header">
188
+ <table border="0" cellpadding="0" cellspacing="0">
189
+ <tr>
190
+ <td style="vertical-align: middle; padding-right: 8px; font-size: 20px;">✨</td>
191
+ <td style="vertical-align: middle;"><h2 class="section-title">Key Highlights</h2></td>
192
+ </tr>
193
+ </table>
236
194
  </div>
237
195
  <div class="list-container">
238
196
  {{#each key_highlights}}
239
- <div class="list-item">
240
- <div class="list-item-text">{{this}}</div>
241
- </div>
197
+ <div class="list-item">{{{this}}}</div>
242
198
  {{/each}}
243
199
  </div>
244
200
  </div>
@@ -247,15 +203,17 @@
247
203
  <!-- Action Items -->
248
204
  {{#if action_items}}
249
205
  <div class="section">
250
- <div class="section-title">
251
- <span class="section-icon">📋</span>
252
- <span>Action Items</span>
206
+ <div class="section-header">
207
+ <table border="0" cellpadding="0" cellspacing="0">
208
+ <tr>
209
+ <td style="vertical-align: middle; padding-right: 8px; font-size: 20px;">✓</td>
210
+ <td style="vertical-align: middle;"><h2 class="section-title">Action Items</h2></td>
211
+ </tr>
212
+ </table>
253
213
  </div>
254
214
  <div class="list-container">
255
215
  {{#each action_items}}
256
- <div class="list-item">
257
- <div class="list-item-text">{{this}}</div>
258
- </div>
216
+ <div class="list-item">{{{this}}}</div>
259
217
  {{/each}}
260
218
  </div>
261
219
  </div>
@@ -264,33 +222,37 @@
264
222
  <!-- Upcoming Priorities -->
265
223
  {{#if upcoming_priorities}}
266
224
  <div class="section">
267
- <div class="section-title">
268
- <span class="section-icon">🎯</span>
269
- <span>Upcoming Priorities</span>
225
+ <div class="section-header">
226
+ <table border="0" cellpadding="0" cellspacing="0">
227
+ <tr>
228
+ <td style="vertical-align: middle; padding-right: 8px; font-size: 20px;">🎯</td>
229
+ <td style="vertical-align: middle;"><h2 class="section-title">Upcoming Priorities</h2></td>
230
+ </tr>
231
+ </table>
270
232
  </div>
271
233
  <div class="list-container">
272
234
  {{#each upcoming_priorities}}
273
- <div class="list-item">
274
- <div class="list-item-text">{{this}}</div>
275
- </div>
235
+ <div class="list-item">{{{this}}}</div>
276
236
  {{/each}}
277
237
  </div>
278
238
  </div>
279
239
  {{/if}}
280
- </div>
281
240
 
282
- <div class="footer-notice">
283
- <p>You received this email because you have daily organization summaries enabled.</p>
284
- <p><a href="{{settings_url}}">Manage your notification preferences</a></p>
285
- </div>
241
+ <div class="divider"></div>
286
242
 
243
+ <p style="text-align: center; color: #5c5545; font-size: 14px;">
244
+ You received this email because you have daily organization summaries enabled.<br>
245
+ <a href="{{settings_url}}" style="color: #7c3aed;">Manage your notification preferences</a>
246
+ </p>
247
+ </div>
287
248
  <div class="footer">
288
- <p>&copy; {{year}} Heliyos AI. All rights reserved.</p>
289
- <div class="footer-links">
249
+ <p {{year}} {{company_name}}. All rights reserved.</p>
250
+ <p>
290
251
  <a href="{{settings_url}}">Notification Settings</a> |
291
- <span>This is an automated message, please do not reply.</span>
292
- </div>
252
+ This is an automated message, please do not reply.
253
+ </p>
293
254
  </div>
294
255
  </div>
295
256
  </body>
257
+
296
258
  </html>