Add React Router for proper URL navigation and browser history support
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Routes, Route, useNavigate, useParams, useLocation } from 'react-router-dom';
|
||||
import { Book, ChevronRight, Moon, Sun } from 'lucide-react';
|
||||
import BookSelector from './components/BookSelector';
|
||||
import ChapterSelector from './components/ChapterSelector';
|
||||
@@ -9,10 +10,69 @@ interface BookData {
|
||||
books: string[];
|
||||
}
|
||||
|
||||
// Component for the home page
|
||||
function HomePage({ books, formatBookName }: { books: string[], formatBookName: (name: string) => string }) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleBookSelect = (book: string) => {
|
||||
navigate(`/book/${book}`);
|
||||
};
|
||||
|
||||
return <BookSelector books={books} onBookSelect={handleBookSelect} formatBookName={formatBookName} />;
|
||||
}
|
||||
|
||||
// Component for book chapters page
|
||||
function BookPage({ books, formatBookName }: { books: string[], formatBookName: (name: string) => string }) {
|
||||
const { bookName } = useParams<{ bookName: string }>();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleChapterSelect = (chapter: string) => {
|
||||
navigate(`/book/${bookName}/chapter/${chapter}`);
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
navigate('/');
|
||||
};
|
||||
|
||||
if (!bookName || !books.includes(bookName)) {
|
||||
return <div>Book not found</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<ChapterSelector
|
||||
book={bookName}
|
||||
onChapterSelect={handleChapterSelect}
|
||||
onBack={handleBack}
|
||||
formatBookName={formatBookName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Component for chapter reading page
|
||||
function ChapterPage({ formatBookName }: { formatBookName: (name: string) => string }) {
|
||||
const { bookName, chapterNumber } = useParams<{ bookName: string, chapterNumber: string }>();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleBack = () => {
|
||||
navigate(`/book/${bookName}`);
|
||||
};
|
||||
|
||||
if (!bookName || !chapterNumber) {
|
||||
return <div>Chapter not found</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<BibleReader
|
||||
book={bookName}
|
||||
chapter={chapterNumber}
|
||||
onBack={handleBack}
|
||||
formatBookName={formatBookName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [books, setBooks] = useState<string[]>([]);
|
||||
const [selectedBook, setSelectedBook] = useState<string>('');
|
||||
const [selectedChapter, setSelectedChapter] = useState<string>('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [darkMode, setDarkMode] = useState(() => {
|
||||
// Load dark mode preference from localStorage
|
||||
@@ -20,6 +80,8 @@ function App() {
|
||||
return saved ? JSON.parse(saved) : false;
|
||||
});
|
||||
const [error, setError] = useState<string>('');
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Debug logging
|
||||
console.log('App component rendered');
|
||||
@@ -59,23 +121,24 @@ function App() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleBookSelect = (book: string) => {
|
||||
setSelectedBook(book);
|
||||
setSelectedChapter('');
|
||||
// Get current navigation info from URL
|
||||
const getCurrentNavInfo = () => {
|
||||
const pathParts = location.pathname.split('/').filter(Boolean);
|
||||
|
||||
if (pathParts.length === 0) {
|
||||
return { currentBook: null, currentChapter: null };
|
||||
}
|
||||
|
||||
if (pathParts[0] === 'book' && pathParts[1]) {
|
||||
const currentBook = pathParts[1];
|
||||
const currentChapter = pathParts[2] === 'chapter' && pathParts[3] ? pathParts[3] : null;
|
||||
return { currentBook, currentChapter };
|
||||
}
|
||||
|
||||
return { currentBook: null, currentChapter: null };
|
||||
};
|
||||
|
||||
const handleChapterSelect = (chapter: string) => {
|
||||
setSelectedChapter(chapter);
|
||||
};
|
||||
|
||||
const handleBackToBooks = () => {
|
||||
setSelectedBook('');
|
||||
setSelectedChapter('');
|
||||
};
|
||||
|
||||
const handleBackToChapters = () => {
|
||||
setSelectedChapter('');
|
||||
};
|
||||
const { currentBook, currentChapter } = getCurrentNavInfo();
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
@@ -96,37 +159,40 @@ function App() {
|
||||
<div className="flex justify-between items-center h-16">
|
||||
<div className="flex items-center space-x-4">
|
||||
<Book className="h-8 w-8 text-blue-600" />
|
||||
<h1 className="text-xl font-bold text-gray-900 dark:text-gray-100">
|
||||
<button
|
||||
onClick={() => navigate('/')}
|
||||
className="text-xl font-bold text-gray-900 dark:text-gray-100 hover:text-blue-600 dark:hover:text-blue-400"
|
||||
>
|
||||
ESV Bible
|
||||
</h1>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Navigation Breadcrumb */}
|
||||
<div className="flex items-center space-x-2 text-sm text-gray-600 dark:text-gray-400">
|
||||
{selectedBook && (
|
||||
{currentBook && (
|
||||
<>
|
||||
<button
|
||||
onClick={handleBackToBooks}
|
||||
onClick={() => navigate('/')}
|
||||
className="hover:text-blue-600 dark:hover:text-blue-400"
|
||||
>
|
||||
Books
|
||||
</button>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
<span className="font-medium text-gray-900 dark:text-gray-100">
|
||||
{formatBookName(selectedBook)}
|
||||
{formatBookName(currentBook)}
|
||||
</span>
|
||||
{selectedChapter && (
|
||||
{currentChapter && (
|
||||
<>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
<button
|
||||
onClick={handleBackToChapters}
|
||||
onClick={() => navigate(`/book/${currentBook}`)}
|
||||
className="hover:text-blue-600 dark:hover:text-blue-400"
|
||||
>
|
||||
Chapters
|
||||
</button>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
<span className="font-medium text-gray-900 dark:text-gray-100">
|
||||
Chapter {selectedChapter}
|
||||
Chapter {currentChapter}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
@@ -151,23 +217,11 @@ function App() {
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
{!selectedBook ? (
|
||||
<BookSelector books={books} onBookSelect={handleBookSelect} formatBookName={formatBookName} />
|
||||
) : !selectedChapter ? (
|
||||
<ChapterSelector
|
||||
book={selectedBook}
|
||||
onChapterSelect={handleChapterSelect}
|
||||
onBack={handleBackToBooks}
|
||||
formatBookName={formatBookName}
|
||||
/>
|
||||
) : (
|
||||
<BibleReader
|
||||
book={selectedBook}
|
||||
chapter={selectedChapter}
|
||||
onBack={handleBackToChapters}
|
||||
formatBookName={formatBookName}
|
||||
/>
|
||||
)}
|
||||
<Routes>
|
||||
<Route path="/" element={<HomePage books={books} formatBookName={formatBookName} />} />
|
||||
<Route path="/book/:bookName" element={<BookPage books={books} formatBookName={formatBookName} />} />
|
||||
<Route path="/book/:bookName/chapter/:chapterNumber" element={<ChapterPage formatBookName={formatBookName} />} />
|
||||
</Routes>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
|
||||
@@ -8,6 +9,8 @@ const root = ReactDOM.createRoot(
|
||||
);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user