'use client' import { useState, useEffect } from 'react' import { useLocale } from 'next-intl' import { Box, Typography, Button } from '@mui/material' import { BibleChapter, BibleVerse } from '@/types' import { getCachedChapter, cacheChapter } from '@/lib/cache-manager' import { SearchNavigator } from './search-navigator' import { ReadingView } from './reading-view' import { VersDetailsPanel } from './verse-details-panel' import { ReadingSettings } from './reading-settings' interface BookInfo { id: string // UUID orderNum: number bookKey: string name: string chapterCount: number } export function BibleReaderApp() { const locale = useLocale() const [bookId, setBookId] = useState(1) // Genesis (numeric ID from search) const [chapter, setChapter] = useState(1) const [currentChapter, setCurrentChapter] = useState(null) const [selectedVerse, setSelectedVerse] = useState(null) const [detailsPanelOpen, setDetailsPanelOpen] = useState(false) const [settingsOpen, setSettingsOpen] = useState(false) const [loading, setLoading] = useState(true) 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 or when locale changes useEffect(() => { loadBooks() }, [locale]) // Load chapter when bookId or chapter changes useEffect(() => { if (!booksLoading && books.length > 0) { loadChapter(bookId, chapter) } }, [bookId, chapter, booksLoading, books.length]) async function loadBooks() { setBooksLoading(true) setError(null) try { const response = await fetch(`/api/bible/books?locale=${locale}`) 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 { const book = books.find(b => b.orderNum === numericBookId) if (!book) { setError(`Book not found (ID: ${numericBookId})`) setCurrentChapter(null) return } // Try cache first const chapterId = `${book.id}-${chapterNum}` let data = await getCachedChapter(chapterId) // If not cached, fetch from API if (!data) { const response = await fetch(`/api/bible/chapter?book=${book.id}&chapter=${chapterNum}`) 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) } } const handleVerseClick = (verseId: string) => { const verse = currentChapter?.verses.find(v => v.id === verseId) if (verse) { setSelectedVerse(verse) setDetailsPanelOpen(true) } } const handleToggleBookmark = () => { if (!selectedVerse) return const newBookmarks = new Set(bookmarks) if (newBookmarks.has(selectedVerse.id)) { newBookmarks.delete(selectedVerse.id) } else { newBookmarks.add(selectedVerse.id) } setBookmarks(newBookmarks) // TODO: Sync to backend in Phase 2 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 console.log(`Note for verse ${selectedVerse.id}:`, note) } return ( {/* Header with search */} { setBookId(newBookId) setChapter(newChapter) }} /> {/* Reading area */} {!booksLoading && error ? ( {error} ) : booksLoading ? ( Initializing Bible reader... ) : loading ? ( Loading chapter... ) : currentChapter ? ( chapter > 1 && setChapter(chapter - 1)} onNextChapter={() => { const book = books.find(b => b.orderNum === bookId) if (book && chapter < book.chapterCount) { setChapter(chapter + 1) } }} onVerseClick={handleVerseClick} onSettingsOpen={() => setSettingsOpen(true)} hasPrevChapter={chapter > 1} hasNextChapter={(() => { const book = books.find(b => b.orderNum === bookId) return book ? chapter < book.chapterCount : false })()} /> ) : ( Failed to load chapter. Please try again. )} {/* Details panel */} setDetailsPanelOpen(false)} isBookmarked={selectedVerse ? bookmarks.has(selectedVerse.id) : false} onToggleBookmark={handleToggleBookmark} onAddNote={handleAddNote} /> {/* Settings panel */} {settingsOpen && ( setSettingsOpen(false)} /> )} ) }