Make re-engagement email tiers configurable from admin; v1.1.20

Day thresholds and per-tier subject/body/CTA are now editable in the
Email Templates panel. Tier keys are position-based (t1/t2/t3) so
changing day values never re-sends emails already fired.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmert
2026-07-28 16:13:25 -04:00
parent 2732730f5e
commit 57fe34ba47
5 changed files with 66 additions and 33 deletions
+9 -6
View File
@@ -669,11 +669,13 @@ export async function scheduleStudyReminders(sendStudyReminderEmail) {
// ── Study re-engagement scheduler ─────────────────────────────────────────
const REENGAGEMENT_TIERS = [
{ key: '7d', days: 7 },
{ key: '14d', days: 14 },
{ key: '30d', days: 30 },
]
function getReengagementTiers() {
const cfg = state.cachedSiteContent ?? {}
const raw = typeof cfg.studyReengagementDays === 'string' ? cfg.studyReengagementDays : '7,14,30'
const days = raw.split(',').map(s => parseInt(s.trim(), 10)).filter(n => !isNaN(n) && n > 0)
if (days.length === 0) return [{ key: 't1', days: 7 }, { key: 't2', days: 14 }, { key: 't3', days: 30 }]
return days.slice(0, 3).map((d, i) => ({ key: `t${i + 1}`, days: d }))
}
function makeUnsubUrl(userId) {
const secret = process.env.RESEND_WEBHOOK_TOKEN ?? 'siteforge'
@@ -687,6 +689,7 @@ export async function scheduleReengagementEmails(sendStudyReengagementEmail) {
if (!state.cachedSiteContent) return
const now = new Date()
const nowMs = now.getTime()
const tiers = getReengagementTiers()
for (const user of state.studyUsers) {
if (user.studyRemindersEnabled !== true) continue
@@ -713,7 +716,7 @@ export async function scheduleReengagementEmails(sendStudyReengagementEmail) {
? `${base}/study/${firstStudy.slug}`
: `${base}/study`
for (const tier of REENGAGEMENT_TIERS) {
for (const tier of tiers) {
if (daysSinceLogin < tier.days) continue
if (sent[tier.key]) continue