From ce8e959ea46ed74ddfa2c0c1f60c46500bbcad1f Mon Sep 17 00:00:00 2001 From: Daniel Onyejesi Date: Mon, 30 Mar 2026 20:51:11 -0400 Subject: [PATCH] Clean email templates (Linear/Resend style) + LiteLLM Gemini STT Emails: white card, clean typography, dark button, no gradients. Same minimal aesthetic as Linear/Resend/Notion emails. Verify page responses also updated to match. --- src/routes/adminConfig.js | 7 +-- src/routes/auth.js | 101 ++++++++++++++++++++++++-------------- 2 files changed, 69 insertions(+), 39 deletions(-) diff --git a/src/routes/adminConfig.js b/src/routes/adminConfig.js index 15bfbcc..02dc465 100644 --- a/src/routes/adminConfig.js +++ b/src/routes/adminConfig.js @@ -66,11 +66,12 @@ router.post('/config/test-email', async function(req, res) { } var emailWrapper = require('./auth').__emailWrapper; - var btnStyle = require('./auth').__btnStyle; + var btnHtml = require('./auth').__btnHtml; var html = emailWrapper( - '

' + bodyText.replace(/\n/g, '
') + '

' + - (btnStyle ? 'Test Button' : '') + '

Test Email

' + + '

' + bodyText.replace(/\n/g, '
') + '

' + + btnHtml('#', 'Test Button') ); var ok = await sendEmail(to, '[TEST] ' + subject, html); diff --git a/src/routes/auth.js b/src/routes/auth.js index 6c32804..cf81fbc 100644 --- a/src/routes/auth.js +++ b/src/routes/auth.js @@ -38,49 +38,78 @@ function safeAppUrl() { } // ============================================================ -// EMAIL TEMPLATES — responsive, max-width constrained +// EMAIL TEMPLATES — clean, minimal (Linear / Resend style) // ============================================================ function emailWrapper(body) { - return ` - + var siteName = process.env.SITE_NAME || 'Pediatric AI Scribe'; + return ` + + + + + + ${escHtml(siteName)} + - - - -
-`; + + + +
+ + + + + + + + + + + + + + + + +
+ +`; } function btnHtml(href, label) { - return `
- -
`; + return ` + +
+ ${escHtml(label)} +
`; } function linkFallback(url) { - return `

Button not working? Copy this link into your browser:

-

${escHtml(url)}

`; + return `

+ Or copy and paste this link into your browser: +

+

${escHtml(url)}

`; } // Email helper — DB settings override env vars @@ -183,11 +212,11 @@ router.get('/verify-email', async (req, res) => { if (!token) return res.status(400).send('Missing token'); var user = await db.get('SELECT id, name FROM users WHERE verify_token = ? AND verify_expires > ?', [token, Date.now()]); if (!user) { - return res.send('

Invalid or Expired Link

Go to app

'); + return res.send('Link Expired

Link expired or invalid

This verification link has expired. Request a new one from the app.

Go to app'); } await db.run('UPDATE users SET email_verified = true, verify_token = NULL, verify_expires = NULL WHERE id = ?', [user.id]); await db.run('INSERT INTO audit_log (user_id, action) VALUES (?, ?)', [user.id, 'email_verified']); - res.send('

Email Verified!

Welcome, ' + escHtml(user.name) + '!

Open App

'); + res.send('Email Verified

Email verified

Welcome, ' + escHtml(user.name) + '. You\'re all set.

Open app'); } catch (err) { console.error('[Auth] Verify error:', err.message); res.status(500).send('Verification failed. Please try again.'); } });