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

+8 -5
View File
@@ -580,13 +580,16 @@ describe('Home page', () => {
expect(await screen.findByDisplayValue('Title')).toBeInTheDocument();
});
test('a reading plan can be started from Home', async () => {
seedProject(); // the plan card shows once there's at least one project
test('a reading plan can be started from the Reading Plans page', async () => {
seedProject(); // the nav button shows once there's at least one project
const user = userEvent.setup();
await renderApp();
await user.click(screen.getByRole('button', { name: /set goal/i }));
await user.click(screen.getByRole('button', { name: /start plan/i }));
await waitFor(() => expect(JSON.parse(localStorage.getItem('readingPlan'))?.bookAbbrev).toBe('GEN'));
await user.click(screen.getByRole('button', { name: /reading plans/i }));
await user.click((await screen.findAllByRole('button', { name: /^start plan$/i }))[0]);
await waitFor(() => {
const stored = JSON.parse(localStorage.getItem('readingPlanProgress'));
expect(stored?.progress?.[0]?.planId).toBeTruthy();
});
});
});