Add React Router for proper URL navigation and browser history support

This commit is contained in:
Ryderjj89
2025-09-13 16:07:33 -04:00
parent 3597f27b76
commit 61280d6181
2 changed files with 100 additions and 43 deletions

View File

@@ -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>
);

View File

@@ -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>
);