@aglyn/shared-util-email 1.0.0-beta.270 → 1.0.0-beta.272
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.
- package/package.json +3 -3
- package/src/index.d.ts +2 -0
- package/src/index.js +2 -0
- package/src/index.js.map +1 -1
- package/src/lib/mail-provider-resend.d.ts +1 -1
- package/src/lib/mail-provider-resend.js +3 -1
- package/src/lib/mail-provider-resend.js.map +1 -1
- package/src/lib/received-email.d.ts +18 -0
- package/src/lib/received-email.js +22 -1
- package/src/lib/received-email.js.map +1 -1
- package/src/lib/site-care-emails.d.ts +25 -0
- package/src/lib/site-care-emails.js +436 -0
- package/src/lib/site-care-emails.js.map +1 -0
- package/src/lib/site-care-project-emails.d.ts +22 -0
- package/src/lib/site-care-project-emails.js +287 -0
- package/src/lib/site-care-project-emails.js.map +1 -0
- package/src/lib/system-email-catalog.js +215 -2
- package/src/lib/system-email-catalog.js.map +1 -1
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /*==========================================
|
|
17
|
+
* SITE CARE PROJECTS, AS SYSTEM EMAILS (AGL-3970).
|
|
18
|
+
*
|
|
19
|
+
* A flat-quoted project is billed from the staff "Charge for work", and the
|
|
20
|
+
* owner hears about every step of it by email: the confirmation of the
|
|
21
|
+
* quote they accepted (the written record of their yes), each invoice with
|
|
22
|
+
* its pay link, each payment received, and any invoice voided, credited or
|
|
23
|
+
* refunded. Each is its own key so staff can redesign one without the rest.
|
|
24
|
+
* The merge tokens are what
|
|
25
|
+
* `@aglyn/tenant-data-admin/server/site-care-projects` fills.
|
|
26
|
+
*=========================================*/ export const SITE_CARE_PROJECT_ACCEPTANCE_EMAIL_KEY = 'site-care-project-acceptance';
|
|
27
|
+
export const SITE_CARE_PROJECT_INVOICE_EMAIL_KEY = 'site-care-project-invoice';
|
|
28
|
+
export const SITE_CARE_PROJECT_PAID_EMAIL_KEY = 'site-care-project-paid';
|
|
29
|
+
export const SITE_CARE_PROJECT_REVERSED_EMAIL_KEY = 'site-care-project-reversed';
|
|
30
|
+
const SOURCE = 'libs/tenant/data/admin/src/lib/server/site-care-projects.ts';
|
|
31
|
+
const ORG_NAME = {
|
|
32
|
+
name: 'org.name',
|
|
33
|
+
description: 'The workspace the project is for',
|
|
34
|
+
sample: 'Test Org'
|
|
35
|
+
};
|
|
36
|
+
const PROJECT_TITLE = {
|
|
37
|
+
name: 'project.title',
|
|
38
|
+
description: 'The project, as staff named it',
|
|
39
|
+
sample: 'Holiday sale landing page'
|
|
40
|
+
};
|
|
41
|
+
const PROJECT_SCOPE = {
|
|
42
|
+
name: 'project.scope',
|
|
43
|
+
description: 'What the price covers, one deliverable per line',
|
|
44
|
+
sample: '- A landing page for the holiday sale\n- A sign-up form for the sale list'
|
|
45
|
+
};
|
|
46
|
+
const FOOTER = 'You’re receiving this because {{org.name}} has a project with {{brand.productName}}.';
|
|
47
|
+
export const SITE_CARE_PROJECT_SYSTEM_EMAIL_TEMPLATES = [
|
|
48
|
+
{
|
|
49
|
+
key: SITE_CARE_PROJECT_ACCEPTANCE_EMAIL_KEY,
|
|
50
|
+
name: 'Site Care project: quote accepted',
|
|
51
|
+
description: 'Sent to the workspace owner the moment staff record their yes to a flat project quote, and again, marked corrected, when the record is corrected. It is the written record of the scope and price they accepted, sent before anything is invoiced.',
|
|
52
|
+
deliveredBy: 'resend',
|
|
53
|
+
defaultSubject: '{{acceptance.heading}}: {{project.title}}',
|
|
54
|
+
mergeTokens: [
|
|
55
|
+
ORG_NAME,
|
|
56
|
+
PROJECT_TITLE,
|
|
57
|
+
PROJECT_SCOPE,
|
|
58
|
+
{
|
|
59
|
+
name: 'acceptance.heading',
|
|
60
|
+
description: '“You accepted our quote”, or “Corrected” on a correction',
|
|
61
|
+
sample: 'You accepted our quote'
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'acceptance.sentence',
|
|
65
|
+
description: 'The price, how it is billed, and how and when the owner said yes',
|
|
66
|
+
sample: 'You accepted our quote for “Holiday sale landing page”: $249, paid in full before work starts. You said yes in person on Oct 19, 2026, 2:10 PM CDT.'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'acceptance.correction',
|
|
70
|
+
description: 'What was corrected and why, on a correction; blank otherwise',
|
|
71
|
+
sample: 'This corrects the earlier record: the owner said yes by phone, not in person.'
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
defaultBody: [
|
|
75
|
+
{
|
|
76
|
+
block: 'text',
|
|
77
|
+
text: 'Project · {{org.name}}',
|
|
78
|
+
variant: 'eyebrow'
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
block: 'text',
|
|
82
|
+
text: '{{acceptance.heading}}',
|
|
83
|
+
variant: 'heading'
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
block: 'text',
|
|
87
|
+
text: '{{acceptance.sentence}} {{acceptance.correction}}',
|
|
88
|
+
variant: 'body'
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
block: 'text',
|
|
92
|
+
text: 'Project: {{project.title}}\n{{project.scope}}',
|
|
93
|
+
variant: 'details'
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
block: 'text',
|
|
97
|
+
text: 'The price is fixed now that you have it: if the work takes us longer, that is ours. We send the invoice next, to pay from your phone. If this is not what you agreed to, reply to this email before you pay.',
|
|
98
|
+
variant: 'caption'
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
footerReason: FOOTER,
|
|
102
|
+
source: SOURCE
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
key: SITE_CARE_PROJECT_INVOICE_EMAIL_KEY,
|
|
106
|
+
name: 'Site Care project: invoice to pay',
|
|
107
|
+
description: 'Sent to the workspace owner with each project invoice — the deposit, the balance at launch, or the whole price — and its secure pay link.',
|
|
108
|
+
deliveredBy: 'resend',
|
|
109
|
+
defaultSubject: '{{invoice.heading}}: {{project.title}}',
|
|
110
|
+
mergeTokens: [
|
|
111
|
+
ORG_NAME,
|
|
112
|
+
PROJECT_TITLE,
|
|
113
|
+
PROJECT_SCOPE,
|
|
114
|
+
{
|
|
115
|
+
name: 'invoice.heading',
|
|
116
|
+
description: '“Your deposit invoice”, “Your balance invoice” or “Your invoice”',
|
|
117
|
+
sample: 'Your invoice'
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'invoice.sentence',
|
|
121
|
+
description: 'What this invoice is for and what is left after it',
|
|
122
|
+
sample: 'This is the $249 for “Holiday sale landing page”, in full. Tax is added at checkout.'
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'invoice.amount',
|
|
126
|
+
description: 'The invoice total, tax included',
|
|
127
|
+
sample: '$269.54'
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: 'invoice.number',
|
|
131
|
+
description: 'The invoice number',
|
|
132
|
+
sample: 'A1B2C3D4-0001'
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: 'invoice.due',
|
|
136
|
+
description: 'When it is due',
|
|
137
|
+
sample: 'Nov 2, 2026'
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: 'invoice.payUrl',
|
|
141
|
+
description: 'The secure page the invoice is paid on',
|
|
142
|
+
sample: 'https://invoice.stripe.com/i/acct_test/test'
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
defaultBody: [
|
|
146
|
+
{
|
|
147
|
+
block: 'text',
|
|
148
|
+
text: 'Project · {{org.name}}',
|
|
149
|
+
variant: 'eyebrow'
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
block: 'text',
|
|
153
|
+
text: '{{invoice.heading}}',
|
|
154
|
+
variant: 'heading'
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
block: 'text',
|
|
158
|
+
text: '{{invoice.sentence}}',
|
|
159
|
+
variant: 'body'
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
block: 'text',
|
|
163
|
+
text: 'Amount: {{invoice.amount}}\nInvoice: {{invoice.number}}\nDue: {{invoice.due}}',
|
|
164
|
+
variant: 'details'
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
block: 'button',
|
|
168
|
+
label: 'Pay the invoice',
|
|
169
|
+
href: '{{invoice.payUrl}}'
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
block: 'text',
|
|
173
|
+
text: 'You can pay by card on your phone or computer. Questions about it? Reply to this email.',
|
|
174
|
+
variant: 'caption'
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
footerReason: FOOTER,
|
|
178
|
+
source: SOURCE
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
key: SITE_CARE_PROJECT_PAID_EMAIL_KEY,
|
|
182
|
+
name: 'Site Care project: payment received',
|
|
183
|
+
description: 'Sent to the workspace owner when a project invoice is paid: what was paid, and what happens next.',
|
|
184
|
+
deliveredBy: 'resend',
|
|
185
|
+
defaultSubject: 'Payment received: {{project.title}}',
|
|
186
|
+
mergeTokens: [
|
|
187
|
+
ORG_NAME,
|
|
188
|
+
PROJECT_TITLE,
|
|
189
|
+
{
|
|
190
|
+
name: 'payment.amount',
|
|
191
|
+
description: 'What was paid, tax included',
|
|
192
|
+
sample: '$269.54'
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: 'payment.sentence',
|
|
196
|
+
description: 'What the payment was for',
|
|
197
|
+
sample: 'Thank you. We received your payment of $269.54 for “Holiday sale landing page”.'
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: 'payment.next',
|
|
201
|
+
description: 'What happens next',
|
|
202
|
+
sample: 'The project is paid in full. We will let you know when it is live.'
|
|
203
|
+
}
|
|
204
|
+
],
|
|
205
|
+
defaultBody: [
|
|
206
|
+
{
|
|
207
|
+
block: 'text',
|
|
208
|
+
text: 'Project · {{org.name}}',
|
|
209
|
+
variant: 'eyebrow'
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
block: 'text',
|
|
213
|
+
text: 'Payment received',
|
|
214
|
+
variant: 'heading'
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
block: 'text',
|
|
218
|
+
text: '{{payment.sentence}} {{payment.next}}',
|
|
219
|
+
variant: 'body'
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
block: 'text',
|
|
223
|
+
text: 'Project: {{project.title}}\nPaid: {{payment.amount}}',
|
|
224
|
+
variant: 'details'
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
block: 'text',
|
|
228
|
+
text: 'Your receipt and the invoice are on Billing in your workspace.',
|
|
229
|
+
variant: 'caption'
|
|
230
|
+
}
|
|
231
|
+
],
|
|
232
|
+
footerReason: FOOTER,
|
|
233
|
+
source: SOURCE
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
key: SITE_CARE_PROJECT_REVERSED_EMAIL_KEY,
|
|
237
|
+
name: 'Site Care project: invoice voided, credited or refunded',
|
|
238
|
+
description: 'Sent to the workspace owner when staff void, credit or refund a project invoice from the project record.',
|
|
239
|
+
deliveredBy: 'resend',
|
|
240
|
+
defaultSubject: '{{reversal.heading}}: {{project.title}}',
|
|
241
|
+
mergeTokens: [
|
|
242
|
+
ORG_NAME,
|
|
243
|
+
PROJECT_TITLE,
|
|
244
|
+
{
|
|
245
|
+
name: 'reversal.heading',
|
|
246
|
+
description: '“Invoice canceled”, “Invoice credited” or “Payment refunded”',
|
|
247
|
+
sample: 'Invoice canceled'
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
name: 'reversal.sentence',
|
|
251
|
+
description: 'What happened to the money',
|
|
252
|
+
sample: 'We canceled the $124.50 deposit invoice for “Holiday sale landing page”. You do not owe it.'
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
name: 'reversal.reason',
|
|
256
|
+
description: 'Why',
|
|
257
|
+
sample: 'The invoice went out with the wrong scope.'
|
|
258
|
+
}
|
|
259
|
+
],
|
|
260
|
+
defaultBody: [
|
|
261
|
+
{
|
|
262
|
+
block: 'text',
|
|
263
|
+
text: 'Project · {{org.name}}',
|
|
264
|
+
variant: 'eyebrow'
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
block: 'text',
|
|
268
|
+
text: '{{reversal.heading}}',
|
|
269
|
+
variant: 'heading'
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
block: 'text',
|
|
273
|
+
text: '{{reversal.sentence}}',
|
|
274
|
+
variant: 'body'
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
block: 'text',
|
|
278
|
+
text: 'Project: {{project.title}}\nWhy: {{reversal.reason}}',
|
|
279
|
+
variant: 'details'
|
|
280
|
+
}
|
|
281
|
+
],
|
|
282
|
+
footerReason: FOOTER,
|
|
283
|
+
source: SOURCE
|
|
284
|
+
}
|
|
285
|
+
];
|
|
286
|
+
|
|
287
|
+
//# sourceMappingURL=site-care-project-emails.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/shared/util/email/src/lib/site-care-project-emails.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*==========================================\n * SITE CARE PROJECTS, AS SYSTEM EMAILS (AGL-3970).\n *\n * A flat-quoted project is billed from the staff \"Charge for work\", and the\n * owner hears about every step of it by email: the confirmation of the\n * quote they accepted (the written record of their yes), each invoice with\n * its pay link, each payment received, and any invoice voided, credited or\n * refunded. Each is its own key so staff can redesign one without the rest.\n * The merge tokens are what\n * `@aglyn/tenant-data-admin/server/site-care-projects` fills.\n *=========================================*/\n\nimport type {\n SystemEmailMergeToken,\n SystemEmailTemplateDefinition,\n} from './system-email-catalog'\n\nexport const SITE_CARE_PROJECT_ACCEPTANCE_EMAIL_KEY = 'site-care-project-acceptance'\nexport const SITE_CARE_PROJECT_INVOICE_EMAIL_KEY = 'site-care-project-invoice'\nexport const SITE_CARE_PROJECT_PAID_EMAIL_KEY = 'site-care-project-paid'\nexport const SITE_CARE_PROJECT_REVERSED_EMAIL_KEY = 'site-care-project-reversed'\n\nconst SOURCE = 'libs/tenant/data/admin/src/lib/server/site-care-projects.ts'\n\nconst ORG_NAME: SystemEmailMergeToken = {\n name: 'org.name',\n description: 'The workspace the project is for',\n sample: 'Test Org',\n}\nconst PROJECT_TITLE: SystemEmailMergeToken = {\n name: 'project.title',\n description: 'The project, as staff named it',\n sample: 'Holiday sale landing page',\n}\nconst PROJECT_SCOPE: SystemEmailMergeToken = {\n name: 'project.scope',\n description: 'What the price covers, one deliverable per line',\n sample: '- A landing page for the holiday sale\\n- A sign-up form for the sale list',\n}\n\nconst FOOTER = 'You’re receiving this because {{org.name}} has a project with {{brand.productName}}.'\n\nexport const SITE_CARE_PROJECT_SYSTEM_EMAIL_TEMPLATES: readonly SystemEmailTemplateDefinition[] = [\n {\n key: SITE_CARE_PROJECT_ACCEPTANCE_EMAIL_KEY,\n name: 'Site Care project: quote accepted',\n description:\n 'Sent to the workspace owner the moment staff record their yes to a flat project quote, and again, marked corrected, when the record is corrected. It is the written record of the scope and price they accepted, sent before anything is invoiced.',\n deliveredBy: 'resend',\n defaultSubject: '{{acceptance.heading}}: {{project.title}}',\n mergeTokens: [\n ORG_NAME,\n PROJECT_TITLE,\n PROJECT_SCOPE,\n {\n name: 'acceptance.heading',\n description: '“You accepted our quote”, or “Corrected” on a correction',\n sample: 'You accepted our quote',\n },\n {\n name: 'acceptance.sentence',\n description: 'The price, how it is billed, and how and when the owner said yes',\n sample:\n 'You accepted our quote for “Holiday sale landing page”: $249, paid in full before work starts. You said yes in person on Oct 19, 2026, 2:10 PM CDT.',\n },\n {\n name: 'acceptance.correction',\n description: 'What was corrected and why, on a correction; blank otherwise',\n sample: 'This corrects the earlier record: the owner said yes by phone, not in person.',\n },\n ],\n defaultBody: [\n { block: 'text', text: 'Project · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{acceptance.heading}}', variant: 'heading' },\n { block: 'text', text: '{{acceptance.sentence}} {{acceptance.correction}}', variant: 'body' },\n { block: 'text', text: 'Project: {{project.title}}\\n{{project.scope}}', variant: 'details' },\n {\n block: 'text',\n text: 'The price is fixed now that you have it: if the work takes us longer, that is ours. We send the invoice next, to pay from your phone. If this is not what you agreed to, reply to this email before you pay.',\n variant: 'caption',\n },\n ],\n footerReason: FOOTER,\n source: SOURCE,\n },\n {\n key: SITE_CARE_PROJECT_INVOICE_EMAIL_KEY,\n name: 'Site Care project: invoice to pay',\n description:\n 'Sent to the workspace owner with each project invoice — the deposit, the balance at launch, or the whole price — and its secure pay link.',\n deliveredBy: 'resend',\n defaultSubject: '{{invoice.heading}}: {{project.title}}',\n mergeTokens: [\n ORG_NAME,\n PROJECT_TITLE,\n PROJECT_SCOPE,\n {\n name: 'invoice.heading',\n description: '“Your deposit invoice”, “Your balance invoice” or “Your invoice”',\n sample: 'Your invoice',\n },\n {\n name: 'invoice.sentence',\n description: 'What this invoice is for and what is left after it',\n sample: 'This is the $249 for “Holiday sale landing page”, in full. Tax is added at checkout.',\n },\n { name: 'invoice.amount', description: 'The invoice total, tax included', sample: '$269.54' },\n { name: 'invoice.number', description: 'The invoice number', sample: 'A1B2C3D4-0001' },\n { name: 'invoice.due', description: 'When it is due', sample: 'Nov 2, 2026' },\n {\n name: 'invoice.payUrl',\n description: 'The secure page the invoice is paid on',\n sample: 'https://invoice.stripe.com/i/acct_test/test',\n },\n ],\n defaultBody: [\n { block: 'text', text: 'Project · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{invoice.heading}}', variant: 'heading' },\n { block: 'text', text: '{{invoice.sentence}}', variant: 'body' },\n {\n block: 'text',\n text: 'Amount: {{invoice.amount}}\\nInvoice: {{invoice.number}}\\nDue: {{invoice.due}}',\n variant: 'details',\n },\n { block: 'button', label: 'Pay the invoice', href: '{{invoice.payUrl}}' },\n {\n block: 'text',\n text: 'You can pay by card on your phone or computer. Questions about it? Reply to this email.',\n variant: 'caption',\n },\n ],\n footerReason: FOOTER,\n source: SOURCE,\n },\n {\n key: SITE_CARE_PROJECT_PAID_EMAIL_KEY,\n name: 'Site Care project: payment received',\n description:\n 'Sent to the workspace owner when a project invoice is paid: what was paid, and what happens next.',\n deliveredBy: 'resend',\n defaultSubject: 'Payment received: {{project.title}}',\n mergeTokens: [\n ORG_NAME,\n PROJECT_TITLE,\n { name: 'payment.amount', description: 'What was paid, tax included', sample: '$269.54' },\n {\n name: 'payment.sentence',\n description: 'What the payment was for',\n sample: 'Thank you. We received your payment of $269.54 for “Holiday sale landing page”.',\n },\n {\n name: 'payment.next',\n description: 'What happens next',\n sample: 'The project is paid in full. We will let you know when it is live.',\n },\n ],\n defaultBody: [\n { block: 'text', text: 'Project · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: 'Payment received', variant: 'heading' },\n { block: 'text', text: '{{payment.sentence}} {{payment.next}}', variant: 'body' },\n { block: 'text', text: 'Project: {{project.title}}\\nPaid: {{payment.amount}}', variant: 'details' },\n {\n block: 'text',\n text: 'Your receipt and the invoice are on Billing in your workspace.',\n variant: 'caption',\n },\n ],\n footerReason: FOOTER,\n source: SOURCE,\n },\n {\n key: SITE_CARE_PROJECT_REVERSED_EMAIL_KEY,\n name: 'Site Care project: invoice voided, credited or refunded',\n description:\n 'Sent to the workspace owner when staff void, credit or refund a project invoice from the project record.',\n deliveredBy: 'resend',\n defaultSubject: '{{reversal.heading}}: {{project.title}}',\n mergeTokens: [\n ORG_NAME,\n PROJECT_TITLE,\n {\n name: 'reversal.heading',\n description: '“Invoice canceled”, “Invoice credited” or “Payment refunded”',\n sample: 'Invoice canceled',\n },\n {\n name: 'reversal.sentence',\n description: 'What happened to the money',\n sample: 'We canceled the $124.50 deposit invoice for “Holiday sale landing page”. You do not owe it.',\n },\n { name: 'reversal.reason', description: 'Why', sample: 'The invoice went out with the wrong scope.' },\n ],\n defaultBody: [\n { block: 'text', text: 'Project · {{org.name}}', variant: 'eyebrow' },\n { block: 'text', text: '{{reversal.heading}}', variant: 'heading' },\n { block: 'text', text: '{{reversal.sentence}}', variant: 'body' },\n { block: 'text', text: 'Project: {{project.title}}\\nWhy: {{reversal.reason}}', variant: 'details' },\n ],\n footerReason: FOOTER,\n source: SOURCE,\n },\n]\n"],"names":["SITE_CARE_PROJECT_ACCEPTANCE_EMAIL_KEY","SITE_CARE_PROJECT_INVOICE_EMAIL_KEY","SITE_CARE_PROJECT_PAID_EMAIL_KEY","SITE_CARE_PROJECT_REVERSED_EMAIL_KEY","SOURCE","ORG_NAME","name","description","sample","PROJECT_TITLE","PROJECT_SCOPE","FOOTER","SITE_CARE_PROJECT_SYSTEM_EMAIL_TEMPLATES","key","deliveredBy","defaultSubject","mergeTokens","defaultBody","block","text","variant","footerReason","source","label","href"],"mappings":"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"}
|
|
@@ -59,6 +59,8 @@ import { EMAIL_NODE_ROOT_ID } from "./email-render.js";
|
|
|
59
59
|
import { domainSystemEmailTemplates } from "./domain-emails.js";
|
|
60
60
|
import { RISK_NOTICE_SYSTEM_EMAIL_TEMPLATES } from "./risk-notice-emails.js";
|
|
61
61
|
import { retentionSystemEmailTemplates } from "./retention-emails.js";
|
|
62
|
+
import { SITE_CARE_SYSTEM_EMAIL_TEMPLATES } from "./site-care-emails.js";
|
|
63
|
+
import { SITE_CARE_PROJECT_SYSTEM_EMAIL_TEMPLATES } from "./site-care-project-emails.js";
|
|
62
64
|
import { welcomeEmailMergeValues } from "./welcome-email.js";
|
|
63
65
|
/** The welcome email's next steps, as a new workspace's owner gets them. */ const WELCOME_SAMPLES = welcomeEmailMergeValues({
|
|
64
66
|
orgName: 'Test Org',
|
|
@@ -238,6 +240,85 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
|
|
|
238
240
|
footerReason: 'You’re receiving this because someone invited you to take over ' + '{{org.name}} on {{brand.productName}}.',
|
|
239
241
|
source: 'apps/console/app/api/orgs/invites/route.ts'
|
|
240
242
|
},
|
|
243
|
+
{
|
|
244
|
+
key: 'org-owner-handoff-proposal',
|
|
245
|
+
name: 'Workspace handoff with a plan',
|
|
246
|
+
description: 'Sent when the platform team hands a workspace to a new owner and ' + 'proposes its plan in the same step: the invitation, with a link to ' + 'Billing where the plan, add-ons, cadence and coupon are already chosen.',
|
|
247
|
+
deliveredBy: 'resend',
|
|
248
|
+
defaultSubject: '{{org.name}} is ready for you on {{brand.productName}}',
|
|
249
|
+
mergeTokens: [
|
|
250
|
+
{
|
|
251
|
+
name: 'org.name',
|
|
252
|
+
description: 'Name of the workspace being handed over',
|
|
253
|
+
sample: 'Test Org'
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
name: 'handoff.previousOwner',
|
|
257
|
+
description: 'What happens to the current owner once the handoff is accepted',
|
|
258
|
+
sample: 'The current owner stays on as an admin.'
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
name: 'plan.name',
|
|
262
|
+
description: 'The proposed plan',
|
|
263
|
+
sample: 'Starter'
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: 'proposal.summary',
|
|
267
|
+
description: 'The plan with the add-ons, cadence and coupon proposed with it',
|
|
268
|
+
sample: 'Starter with Site Care, billed yearly, code BOOTH25'
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
name: 'proposal.note',
|
|
272
|
+
description: 'A line from the team, or nothing when none was written',
|
|
273
|
+
sample: 'Great meeting you at the booth.'
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
name: 'billingUrl',
|
|
277
|
+
description: 'Billing page with the bundle preselected; signing in with this ' + 'address shows the invitation to accept first',
|
|
278
|
+
sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/billing?plan=starter&interval=year&addons=siteCare`
|
|
279
|
+
}
|
|
280
|
+
],
|
|
281
|
+
// Mirrors the fallback text in invites/route.ts.
|
|
282
|
+
defaultBody: [
|
|
283
|
+
{
|
|
284
|
+
block: 'text',
|
|
285
|
+
text: 'Your new website · {{org.name}}',
|
|
286
|
+
variant: 'eyebrow'
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
block: 'text',
|
|
290
|
+
text: '{{org.name}} is ready for you',
|
|
291
|
+
variant: 'heading'
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
block: 'text',
|
|
295
|
+
text: 'You\'ve been invited to take over {{org.name}} as its owner. The owner holds the workspace, every site in it, and its billing. {{handoff.previousOwner}}',
|
|
296
|
+
variant: 'body'
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
block: 'text',
|
|
300
|
+
text: '{{proposal.note}}',
|
|
301
|
+
variant: 'body'
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
block: 'text',
|
|
305
|
+
text: 'Your plan: {{proposal.summary}}',
|
|
306
|
+
variant: 'details'
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
block: 'button',
|
|
310
|
+
label: 'Accept and start the {{plan.name}} plan',
|
|
311
|
+
href: '{{billingUrl}}'
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
block: 'text',
|
|
315
|
+
text: 'Sign in with this email address, accept the invitation, and Billing opens with everything already chosen. Nothing is charged until you confirm.',
|
|
316
|
+
variant: 'caption'
|
|
317
|
+
}
|
|
318
|
+
],
|
|
319
|
+
footerReason: 'You’re receiving this because the {{brand.productName}} team invited ' + 'you to take over {{org.name}}.',
|
|
320
|
+
source: 'apps/console/app/api/orgs/invites/route.ts'
|
|
321
|
+
},
|
|
241
322
|
{
|
|
242
323
|
key: 'org-upgrade-proposal',
|
|
243
324
|
name: 'Upgrade proposal',
|
|
@@ -260,10 +341,15 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
|
|
|
260
341
|
description: 'A line from the team, or nothing when none was written',
|
|
261
342
|
sample: 'As we discussed on Tuesday.'
|
|
262
343
|
},
|
|
344
|
+
{
|
|
345
|
+
name: 'proposal.summary',
|
|
346
|
+
description: 'The plan with the add-ons, cadence and coupon proposed with it, ' + 'or nothing when only a plan was proposed',
|
|
347
|
+
sample: 'Starter with Site Care, billed yearly, code BOOTH25'
|
|
348
|
+
},
|
|
263
349
|
{
|
|
264
350
|
name: 'billingUrl',
|
|
265
|
-
description: 'Billing page with the proposed plan preselected',
|
|
266
|
-
sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/billing?plan=starter`
|
|
351
|
+
description: 'Billing page with the proposed plan, add-ons, cadence and coupon preselected',
|
|
352
|
+
sample: `${SAMPLE_CONSOLE_ORIGIN}/test-org/billing?plan=starter&interval=year&addons=siteCare`
|
|
267
353
|
}
|
|
268
354
|
],
|
|
269
355
|
// Mirrors the fallback text in /api/admin/org-upgrade-proposal.
|
|
@@ -283,6 +369,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
|
|
|
283
369
|
text: 'Your {{brand.productName}} team proposed moving {{org.name}} to the {{plan.name}} plan.',
|
|
284
370
|
variant: 'body'
|
|
285
371
|
},
|
|
372
|
+
{
|
|
373
|
+
block: 'text',
|
|
374
|
+
text: '{{proposal.summary}}',
|
|
375
|
+
variant: 'details'
|
|
376
|
+
},
|
|
286
377
|
{
|
|
287
378
|
block: 'text',
|
|
288
379
|
text: '{{proposal.note}}',
|
|
@@ -307,6 +398,65 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
|
|
|
307
398
|
footerReason: 'You’re receiving this because you own {{org.name}} on ' + '{{brand.productName}} and its team proposed a plan for it.',
|
|
308
399
|
source: 'apps/console/app/api/admin/org-upgrade-proposal/route.ts'
|
|
309
400
|
},
|
|
401
|
+
{
|
|
402
|
+
key: 'client-build-preview',
|
|
403
|
+
name: 'Client build preview',
|
|
404
|
+
description: 'Sent to a business owner when the platform team has built their ' + 'website with them, at an event or on their doorstep, with the link ' + 'to look at it and the address it will live at.',
|
|
405
|
+
deliveredBy: 'resend',
|
|
406
|
+
defaultSubject: 'Your new website for {{business.name}} is ready to look at',
|
|
407
|
+
mergeTokens: [
|
|
408
|
+
{
|
|
409
|
+
name: 'business.name',
|
|
410
|
+
description: 'Name of the business the website was built for',
|
|
411
|
+
sample: 'Harbor Plumbing'
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
name: 'preview.url',
|
|
415
|
+
description: 'Where the website can be seen now',
|
|
416
|
+
sample: 'https://harbor-plumbing.example.com'
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
name: 'site.address',
|
|
420
|
+
description: 'The address the website will live at: the domain the owner chose, or its free address',
|
|
421
|
+
sample: 'www.example.com'
|
|
422
|
+
}
|
|
423
|
+
],
|
|
424
|
+
// Mirrors the fallback text in libs/tenant/data/admin/src/lib/server/client-build.ts.
|
|
425
|
+
defaultBody: [
|
|
426
|
+
{
|
|
427
|
+
block: 'text',
|
|
428
|
+
text: '{{business.name}}',
|
|
429
|
+
variant: 'eyebrow'
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
block: 'text',
|
|
433
|
+
text: 'Your new website is ready to look at',
|
|
434
|
+
variant: 'heading'
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
block: 'text',
|
|
438
|
+
text: 'We built the website for {{business.name}} with you today. Open it on your phone and look around: every page, picture and word can still be changed.',
|
|
439
|
+
variant: 'body'
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
block: 'text',
|
|
443
|
+
text: 'Website: {{preview.url}}\nAddress: {{site.address}}',
|
|
444
|
+
variant: 'details'
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
block: 'button',
|
|
448
|
+
label: 'See your website',
|
|
449
|
+
href: '{{preview.url}}'
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
block: 'text',
|
|
453
|
+
text: 'Nothing is charged until you choose a plan.',
|
|
454
|
+
variant: 'caption'
|
|
455
|
+
}
|
|
456
|
+
],
|
|
457
|
+
footerReason: 'You’re receiving this because the {{brand.productName}} team built a ' + 'website for {{business.name}} with you and you gave us this address.',
|
|
458
|
+
source: 'apps/console/app/api/admin/client-build/route.ts'
|
|
459
|
+
},
|
|
310
460
|
{
|
|
311
461
|
key: 'usage-summary',
|
|
312
462
|
name: 'Monthly usage summary',
|
|
@@ -1663,6 +1813,64 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
|
|
|
1663
1813
|
footerReason: 'You’re receiving this because a member of {{org.name}} on ' + '{{brand.productName}} asked to add this address to their account.',
|
|
1664
1814
|
source: 'libs/tenant/data/admin/src/lib/server/member-email-aliases.ts'
|
|
1665
1815
|
},
|
|
1816
|
+
{
|
|
1817
|
+
key: 'domain-ownership-code',
|
|
1818
|
+
name: 'Website ownership code',
|
|
1819
|
+
description: 'Sent to an address at a website’s own domain when a workspace ' + 'proves it owns that website before bringing it into the product. ' + 'Carries a six-digit code that works for 15 minutes.',
|
|
1820
|
+
deliveredBy: 'resend',
|
|
1821
|
+
defaultSubject: 'Your code to verify {{domain}}',
|
|
1822
|
+
mergeTokens: [
|
|
1823
|
+
{
|
|
1824
|
+
name: 'org.name',
|
|
1825
|
+
description: 'The workspace that asked',
|
|
1826
|
+
sample: 'Test Org'
|
|
1827
|
+
},
|
|
1828
|
+
{
|
|
1829
|
+
name: 'domain',
|
|
1830
|
+
description: 'The website’s domain',
|
|
1831
|
+
sample: 'example.com'
|
|
1832
|
+
},
|
|
1833
|
+
{
|
|
1834
|
+
name: 'code',
|
|
1835
|
+
description: 'The one-time code',
|
|
1836
|
+
sample: '123456'
|
|
1837
|
+
},
|
|
1838
|
+
{
|
|
1839
|
+
name: 'expiresInMinutes',
|
|
1840
|
+
description: 'How many minutes the code works',
|
|
1841
|
+
sample: '15'
|
|
1842
|
+
}
|
|
1843
|
+
],
|
|
1844
|
+
defaultBody: [
|
|
1845
|
+
{
|
|
1846
|
+
block: 'text',
|
|
1847
|
+
text: '{{domain}}',
|
|
1848
|
+
variant: 'eyebrow'
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
block: 'text',
|
|
1852
|
+
text: 'Your verification code',
|
|
1853
|
+
variant: 'heading'
|
|
1854
|
+
},
|
|
1855
|
+
{
|
|
1856
|
+
block: 'text',
|
|
1857
|
+
text: '{{org.name}} asked to confirm that {{domain}} belongs to them, so they can bring the site into {{brand.productName}}. Type this code where you asked for it.',
|
|
1858
|
+
variant: 'body'
|
|
1859
|
+
},
|
|
1860
|
+
{
|
|
1861
|
+
block: 'text',
|
|
1862
|
+
text: 'Code: {{code}}\nWebsite: {{domain}}\nWorks for: {{expiresInMinutes}} minutes',
|
|
1863
|
+
variant: 'details'
|
|
1864
|
+
},
|
|
1865
|
+
{
|
|
1866
|
+
block: 'text',
|
|
1867
|
+
text: 'If you did not ask for this, ignore this email. Nothing is copied from your site without the code.',
|
|
1868
|
+
variant: 'caption'
|
|
1869
|
+
}
|
|
1870
|
+
],
|
|
1871
|
+
footerReason: 'You’re receiving this because someone in {{org.name}} on ' + '{{brand.productName}} asked to verify a website at this address’s domain.',
|
|
1872
|
+
source: 'libs/tenant/data/admin/src/lib/server/domain-ownership.ts'
|
|
1873
|
+
},
|
|
1666
1874
|
{
|
|
1667
1875
|
key: 'crm-daily-digest',
|
|
1668
1876
|
name: 'Daily CRM digest',
|
|
@@ -2358,6 +2566,11 @@ const BASE_SYSTEM_EMAIL_TEMPLATES = [
|
|
|
2358
2566
|
...BASE_SYSTEM_EMAIL_TEMPLATES,
|
|
2359
2567
|
...RISK_NOTICE_SYSTEM_EMAIL_TEMPLATES,
|
|
2360
2568
|
...retentionSystemEmailTemplates(SAMPLE_CONSOLE_ORIGIN, SAMPLE_DOCS_ORIGIN),
|
|
2569
|
+
// Site Care requests (AGL-3959), beside their own sender's notes.
|
|
2570
|
+
...SITE_CARE_SYSTEM_EMAIL_TEMPLATES,
|
|
2571
|
+
// Site Care projects (AGL-3970): the flat quote's acceptance, invoices,
|
|
2572
|
+
// payments and reversals.
|
|
2573
|
+
...SITE_CARE_PROJECT_SYSTEM_EMAIL_TEMPLATES,
|
|
2361
2574
|
// A domain bought through the domains plugin (AGL-3962), whose keys and
|
|
2362
2575
|
// copy live in `domain-emails.ts`.
|
|
2363
2576
|
...domainSystemEmailTemplates(SAMPLE_CONSOLE_ORIGIN)
|