Add reading plans: catalog, progress tracking, and custom plans

Replaces the old single-book reading goal with a full Reading Plans page:
9 built-in plans (Whole Bible, OT/NT, topical) with cover photos and
color-themed cards, day-by-day checklists synced to the server per user,
inline "mark today read" in the Bible reader, and user-created plans with
their own book picker and an optional uploaded cover photo.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5 committed 2026-09-23 12:51:28 -04:00
1 parent f1026dc194
commit 600b3d3ab9
21 files changed
+1166 -159

No files matched your search

+30
View File
@@ -13,6 +13,7 @@ import {
adminGetAllUsers, adminDeleteUser, adminGetAllProjects, adminGetProject, adminDeleteProject,
setUserPassword, destroyAllSessionsForUser,
getAllReaderInk, setReaderInkPage,
getReadingProgress, setReadingProgress,
} from './db.js';
import { SqliteSessionStore } from './sessionStore.js';
import {
@@ -394,6 +395,35 @@ app.put('/api/reader/ink/:book/:chapter', requireAuth, (req, res) => {
}
});
// ---------------------------------------------------------------------------
// Reading plan progress — cross-device sync for started/completed reading plans
// ---------------------------------------------------------------------------
// GET /api/reading-plans — the current user's whole progress list
app.get('/api/reading-plans', requireAuth, (req, res) => {
try {
res.json(getReadingProgress(req.session.userId));
} catch (err) {
console.error('GET /api/reading-plans error:', err);
res.status(500).json({ error: 'Failed to load reading plan progress.' });
}
});
// PUT /api/reading-plans — overwrite the current user's whole progress list
// (an object: { progress: [...], customPlans: [...] })
app.put('/api/reading-plans', requireAuth, (req, res) => {
try {
if (!req.body || typeof req.body !== 'object' || Array.isArray(req.body)) {
return res.status(400).json({ error: 'Body must be an object.' });
}
setReadingProgress(req.session.userId, req.body);
res.json({ ok: true });
} catch (err) {
console.error('PUT /api/reading-plans error:', err);
res.status(500).json({ error: 'Failed to save reading plan progress.' });
}
});
// ---------------------------------------------------------------------------
// Read-only share links
// ---------------------------------------------------------------------------