diff --git a/components/bible/bible-reader-app.tsx b/components/bible/bible-reader-app.tsx index 875e8c5..5d464be 100644 --- a/components/bible/bible-reader-app.tsx +++ b/components/bible/bible-reader-app.tsx @@ -1,6 +1,6 @@ 'use client' import { useState, useEffect } from 'react' -import { Box } from '@mui/material' +import { Box, Typography, Button } from '@mui/material' import { BibleChapter, BibleVerse } from '@/types' import { getCachedChapter, cacheChapter } from '@/lib/cache-manager' import { SearchNavigator } from './search-navigator' @@ -27,6 +27,8 @@ export function BibleReaderApp() { const [bookmarks, setBookmarks] = useState>(new Set()) const [books, setBooks] = useState([]) const [versionId, setVersionId] = useState('') + const [error, setError] = useState(null) + const [booksLoading, setBooksLoading] = useState(true) // Load books on mount useEffect(() => { @@ -35,40 +37,52 @@ export function BibleReaderApp() { // Load chapter when bookId or chapter changes useEffect(() => { - if (books.length > 0) { + if (!booksLoading && books.length > 0) { loadChapter(bookId, chapter) } - }, [bookId, chapter, books]) + }, [bookId, chapter, booksLoading, books.length]) async function loadBooks() { + setBooksLoading(true) + setError(null) + try { const response = await fetch('/api/bible/books') - if (response.ok) { - const json = await response.json() - if (json.success && json.books) { - const bookMap: BookInfo[] = json.books.map((book: any) => ({ - id: book.id, - orderNum: book.orderNum, - bookKey: book.bookKey, - name: book.name, - chapterCount: book.chapters.length - })) - setBooks(bookMap) - setVersionId(json.version.id) - } + if (!response.ok) { + throw new Error(`Failed to load books: ${response.status}`) + } + + const data = await response.json() + if (data.books && Array.isArray(data.books)) { + const bookMap: BookInfo[] = data.books.map((book: any) => ({ + id: book.id, + orderNum: book.orderNum, + bookKey: book.bookKey, + name: book.name, + chapterCount: book.chapters.length + })) + setBooks(bookMap) + setVersionId(data.version?.id || 'unknown') + } else { + throw new Error('Invalid books response format') } } catch (error) { + const errorMsg = error instanceof Error ? error.message : 'Unknown error loading books' + setError(errorMsg) console.error('Error loading books:', error) + } finally { + setBooksLoading(false) } } async function loadChapter(numericBookId: number, chapterNum: number) { setLoading(true) + setError(null) + try { - // Find the book by orderNum const book = books.find(b => b.orderNum === numericBookId) if (!book) { - console.error('Book not found for orderNum:', numericBookId) + setError(`Book not found (ID: ${numericBookId})`) setCurrentChapter(null) return } @@ -80,24 +94,26 @@ export function BibleReaderApp() { // If not cached, fetch from API if (!data) { const response = await fetch(`/api/bible/chapter?book=${book.id}&chapter=${chapterNum}`) - if (response.ok) { - const json = await response.json() - data = json.chapter - // Cache it - if (data) { - data.id = chapterId - data.bookId = numericBookId // Keep numeric ID for consistency - data.chapter = chapterNum - await cacheChapter(data) - } - } else { - console.error('Failed to load chapter:', response.status) + if (!response.ok) { + throw new Error(`Failed to load chapter: ${response.status} ${response.statusText}`) + } + + const json = await response.json() + data = json.chapter + + // Cache it + if (data) { + data.id = chapterId + await cacheChapter(data).catch(e => console.error('Cache error:', e)) } } setCurrentChapter(data) } catch (error) { + const errorMsg = error instanceof Error ? error.message : 'Unknown error loading chapter' + setError(errorMsg) + setCurrentChapter(null) console.error('Error loading chapter:', error) } finally { setLoading(false) @@ -125,6 +141,25 @@ export function BibleReaderApp() { console.log('Bookmarks updated:', Array.from(newBookmarks)) } + useEffect(() => { + // Persist bookmarks to localStorage + const bookmarkArray = Array.from(bookmarks) + localStorage.setItem('bible-reader-bookmarks', JSON.stringify(bookmarkArray)) + }, [bookmarks]) + + // On mount, load bookmarks from localStorage + useEffect(() => { + const stored = localStorage.getItem('bible-reader-bookmarks') + if (stored) { + try { + const bookmarkArray = JSON.parse(stored) as string[] + setBookmarks(new Set(bookmarkArray)) + } catch (e) { + console.error('Failed to load bookmarks:', e) + } + } + }, []) + const handleAddNote = (note: string) => { if (!selectedVerse) return // TODO: Save note to backend in Phase 2 @@ -156,7 +191,22 @@ export function BibleReaderApp() { {/* Reading area */} - {currentChapter ? ( + {!booksLoading && error ? ( + + {error} + + + ) : booksLoading ? ( + Initializing Bible reader... + ) : loading ? ( + Loading chapter... + ) : currentChapter ? ( ) : ( - {loading ? 'Loading Bible reader...' : 'Failed to load chapter. Please try again.'} + Failed to load chapter. Please try again. )} diff --git a/components/bible/reading-view.tsx b/components/bible/reading-view.tsx index d7fe10e..229627c 100644 --- a/components/bible/reading-view.tsx +++ b/components/bible/reading-view.tsx @@ -32,7 +32,14 @@ export function ReadingView({ const [showControls, setShowControls] = useState(!isMobile) useEffect(() => { + const handleStorageChange = () => { + setPreferences(loadPreferences()) + } + setPreferences(loadPreferences()) + window.addEventListener('storage', handleStorageChange) + + return () => window.removeEventListener('storage', handleStorageChange) }, []) const cssVars = getCSSVariables(preferences)