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:
1 parent
f1026dc194
commit
600b3d3ab9
21 files changed
+1166
-159
No files matched your search
+21
-5
@@ -4,10 +4,10 @@ import { useAudio } from './hooks/useAudio.js';
|
||||
import { useAuth } from './hooks/useAuth.js';
|
||||
import { useBibleReader } from './hooks/useBibleReader.js';
|
||||
import { useProjectLibrary } from './hooks/useProjectLibrary.js';
|
||||
import { useReadingPlan } from './hooks/useReadingPlan.js';
|
||||
import { useReadingPlans } from './hooks/useReadingPlans.js';
|
||||
import { useSharedView } from './hooks/useSharedView.js';
|
||||
import HomePage from './pages/HomePage.jsx';
|
||||
import { saveRemoteProject } from './syncService.js';
|
||||
import { getRemoteReadingProgress, saveRemoteProject } from './syncService.js';
|
||||
import { buildExportHtml, loadProjectIndex, switchStorageUser } from './utils/bibleUtils.jsx';
|
||||
import { migrateOldStorageKeys, saveProjectToStorage } from './utils/projectStorage.js';
|
||||
|
||||
@@ -21,6 +21,7 @@ const SettingsPage = lazy(() => import('./pages/SettingsPage.jsx'));
|
||||
const SetupPage = lazy(() => import('./pages/SetupPage.jsx'));
|
||||
const StudyPage = lazy(() => import('./pages/StudyPage.jsx'));
|
||||
const PronunciationPage = lazy(() => import('./pages/PronunciationPage.jsx'));
|
||||
const ReadingPlansPage = lazy(() => import('./pages/ReadingPlansPage.jsx'));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// App component
|
||||
@@ -28,7 +29,7 @@ const PronunciationPage = lazy(() => import('./pages/PronunciationPage.jsx'));
|
||||
|
||||
const App = () => {
|
||||
const [project, setProject] = useState(null);
|
||||
// 'home' | 'setup' | 'study' | 'reader' | 'import' | 'pronunciation' | 'settings' | 'admin'
|
||||
// 'home' | 'setup' | 'study' | 'reader' | 'import' | 'pronunciation' | 'settings' | 'admin' | 'reading-plans'
|
||||
const [currentPage, setCurrentPage] = useState('home');
|
||||
const [projectIndex, setProjectIndex] = useState([]);
|
||||
const [saveStatus, setSaveStatus] = useState('');
|
||||
@@ -36,7 +37,7 @@ const App = () => {
|
||||
const [syncStatus, setSyncStatus] = useState(''); // '' | 'syncing' | 'synced' | 'error'
|
||||
const reader = useBibleReader(currentPage);
|
||||
const audio = useAudio(reader.readerBookAbbrev, reader.readerChapter);
|
||||
const readingPlan = useReadingPlan();
|
||||
const readingPlans = useReadingPlans();
|
||||
const { authUser, setAuthUser, authServerDown, signIn, logout } = useAuth({
|
||||
onSignIn: (user) => {
|
||||
setProjectIndex(switchStorageUser(user.id));
|
||||
@@ -45,6 +46,10 @@ const App = () => {
|
||||
.then((r) => r.ok ? r.json() : null)
|
||||
.then((serverInk) => { if (serverInk) reader.mergeServerInk(serverInk); })
|
||||
.catch(() => {});
|
||||
// Same for reading plan progress
|
||||
getRemoteReadingProgress().then((result) => {
|
||||
if (result.ok) readingPlans.mergeServerReadingProgress(result.data);
|
||||
});
|
||||
},
|
||||
onSignOut: () => {
|
||||
setProjectIndex(switchStorageUser(null));
|
||||
@@ -110,6 +115,14 @@ const App = () => {
|
||||
// Navigation
|
||||
const openBibleReader = () => setCurrentPage('reader');
|
||||
|
||||
const openReadingPlans = () => setCurrentPage('reading-plans');
|
||||
|
||||
// Jumps straight into a specific plan day's first chapter and opens the reader.
|
||||
const readReadingPlanDay = (bookAbbrev, chapter) => {
|
||||
reader.jumpToReaderVerse(bookAbbrev, chapter, 1);
|
||||
setCurrentPage('reader');
|
||||
};
|
||||
|
||||
const openNewProject = () => {
|
||||
setProject(null);
|
||||
setCurrentPage('setup');
|
||||
@@ -155,8 +168,10 @@ const App = () => {
|
||||
// Home
|
||||
projectIndex,
|
||||
...library,
|
||||
...readingPlan,
|
||||
...readingPlans,
|
||||
openBibleReader,
|
||||
openReadingPlans,
|
||||
readReadingPlanDay,
|
||||
openImportProject,
|
||||
openNewProject,
|
||||
// Audio (book player on Home + chapter player in the Reader)
|
||||
@@ -238,6 +253,7 @@ function AppRouter() {
|
||||
|
||||
if (currentPage === 'admin') return <AdminPage />;
|
||||
if (currentPage === 'settings') return <SettingsPage />;
|
||||
if (currentPage === 'reading-plans') return <ReadingPlansPage />;
|
||||
if (currentPage === 'reader') return <ReaderPage />;
|
||||
if (currentPage === 'import') return <ImportPage />;
|
||||
if (currentPage === 'study') return <StudyPage />;
|
||||
|
||||
Reference in new issue
Block a user