Add study account engagement features; v1.2.4
- Pause reminders: remindersPausedUntil field + scheduler skip + account UI with 7/14/30-day presets - Email digest mode: reminderFrequency field (immediate/weekly) + weekly digest email + scheduler + account UI toggle - Admin user list improvements: streak, reengagement, frequency, pause, per-study lesson progress - Admin manual re-engagement: POST endpoint + tier selector button in admin panel - Study bookmarks: bookmarkedSectionIds in progress file + POST/DELETE endpoints + toggle button in lesson UI - Study completion certificate email: auto-sent on first certificate issuance - Content fields for certificate and weekly digest email templates in admin Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
5bc8245ed2
commit
038ef2b039
12 files changed
+540
-38
No files matched your search
@@ -218,6 +218,8 @@ export function register(app) {
|
||||
displayName: user.displayName ?? '',
|
||||
subscribeNewsletter: user.subscribeNewsletter !== false,
|
||||
studyRemindersEnabled: user.studyRemindersEnabled === true,
|
||||
reminderFrequency: user.reminderFrequency ?? 'immediate',
|
||||
remindersPausedUntil: user.remindersPausedUntil ?? null,
|
||||
avatarUrl: getStudyAvatarUrl(user),
|
||||
},
|
||||
stats: {
|
||||
@@ -303,6 +305,20 @@ export function register(app) {
|
||||
const studyRemindersEnabled = req.body?.studyRemindersEnabled === true
|
||||
user.subscribeNewsletter = subscribeNewsletter
|
||||
user.studyRemindersEnabled = studyRemindersEnabled
|
||||
|
||||
const reminderFrequency = req.body?.reminderFrequency
|
||||
if (reminderFrequency === 'weekly' || reminderFrequency === 'immediate') {
|
||||
user.reminderFrequency = reminderFrequency
|
||||
}
|
||||
|
||||
const rawPaused = req.body?.remindersPausedUntil
|
||||
if (rawPaused === null || rawPaused === '') {
|
||||
user.remindersPausedUntil = null
|
||||
} else if (typeof rawPaused === 'string') {
|
||||
const parsed = new Date(rawPaused)
|
||||
user.remindersPausedUntil = !isNaN(parsed.getTime()) && parsed.getTime() > Date.now() ? parsed.toISOString() : null
|
||||
}
|
||||
|
||||
user.updatedAt = new Date().toISOString()
|
||||
queueStudyUsersWrite()
|
||||
|
||||
@@ -310,7 +326,13 @@ export function register(app) {
|
||||
syncContactToResend(user.displayName || user.username, user.username).catch(err => console.error('[study-account] resend sync error:', err))
|
||||
}
|
||||
|
||||
res.json({ ok: true, subscribeNewsletter: user.subscribeNewsletter, studyRemindersEnabled: user.studyRemindersEnabled === true })
|
||||
res.json({
|
||||
ok: true,
|
||||
subscribeNewsletter: user.subscribeNewsletter,
|
||||
studyRemindersEnabled: user.studyRemindersEnabled === true,
|
||||
reminderFrequency: user.reminderFrequency ?? 'immediate',
|
||||
remindersPausedUntil: user.remindersPausedUntil ?? null,
|
||||
})
|
||||
})
|
||||
|
||||
app.post('/api/study-account/request-email-change', studyAuthRateLimiter, requireStudyAuth, async (req, res) => {
|
||||
|
||||
Reference in new issue
Block a user