diff --git a/public/docs/feedback-request.html b/public/docs/feedback-request.html new file mode 100644 index 0000000..521332c --- /dev/null +++ b/public/docs/feedback-request.html @@ -0,0 +1,127 @@ + + +
+ + + + + + + + + + +
+
|
Hi there,
', - 'It\'s been a little while since we sent your invite, and we would love to hear your thoughts.
', - '', - 'Thank you for helping us improve OpenSquawk!
', - ].join('') + const text = renderFeedbackText() + const html = await renderFeedbackEmail() await sendMail({ to: email, diff --git a/server/utils/invitations.ts b/server/utils/invitations.ts index 9c06f01..fc323a7 100644 --- a/server/utils/invitations.ts +++ b/server/utils/invitations.ts @@ -2,33 +2,45 @@ import { randomBytes } from 'node:crypto' import { readFile } from 'node:fs/promises' import { join } from 'node:path' -let cachedHtmlTemplate: string | null = null +type CachedTemplates = { + invitations: string | null + feedback: string | null +} + +const cachedTemplates: CachedTemplates = { + invitations: null, + feedback: null, +} export function generateInvitationCode() { return randomBytes(4).toString('hex').toUpperCase() } -async function loadInvitationTemplate() { - if (cachedHtmlTemplate) { - return cachedHtmlTemplate +async function loadTemplate(kind: keyof CachedTemplates, filename: string, fallback: string) { + if (cachedTemplates[kind]) { + return cachedTemplates[kind] as string } - const templatePath = join(process.cwd(), 'public', 'docs', 'invites.html') + const templatePath = join(process.cwd(), 'public', 'docs', filename) try { const file = await readFile(templatePath, 'utf8') - cachedHtmlTemplate = file + cachedTemplates[kind] = file return file } catch (error) { - console.warn('Could not load invitation email template, falling back to plain HTML.', error) - const fallback = `Your OpenSquawk invite code: {{INVITE_CODE}}
` - cachedHtmlTemplate = fallback + console.warn(`Could not load ${kind} email template, falling back to plain HTML.`, error) + cachedTemplates[kind] = fallback return fallback } } export async function renderInvitationEmail(code: string) { - const template = await loadInvitationTemplate() + const template = await loadTemplate( + 'invitations', + 'invites.html', + `Your OpenSquawk invite code: {{INVITE_CODE}}
` + ) + return template.replace(/{{INVITE_CODE}}/g, code) } @@ -48,3 +60,28 @@ export function renderInvitationText(code: string) { return lines.join('\n') } + +export async function renderFeedbackEmail() { + const template = await loadTemplate( + 'feedback', + 'feedback-request.html', + `We'd love your feedback: opensquawk.de/feedback
` + ) + + return template +} + +export function renderFeedbackText() { + const lines = [ + 'Hi there,', + '', + "It's been a little while since we sent your invite, and we would love to hear your thoughts.", + '', + 'Share your feedback here:', + 'https://opensquawk.de/feedback', + '', + 'Thank you for helping us improve OpenSquawk!', + ] + + return lines.join('\n') +}