Add clean URL support with book names like /book/Genesis/chapter/1
This commit is contained in:
@@ -11,21 +11,24 @@ interface BookData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Component for the home page
|
// Component for the home page
|
||||||
function HomePage({ books, formatBookName }: { books: string[], formatBookName: (name: string) => string }) {
|
function HomePage({ books, formatBookName, getBookUrlName }: { books: string[], formatBookName: (name: string) => string, getBookUrlName: (name: string) => string }) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const handleBookSelect = (book: string) => {
|
const handleBookSelect = (book: string) => {
|
||||||
navigate(`/book/${book}`);
|
const urlName = getBookUrlName(book);
|
||||||
|
navigate(`/book/${urlName}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
return <BookSelector books={books} onBookSelect={handleBookSelect} formatBookName={formatBookName} />;
|
return <BookSelector books={books} onBookSelect={handleBookSelect} formatBookName={formatBookName} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Component for book chapters page
|
// Component for book chapters page
|
||||||
function BookPage({ books, formatBookName }: { books: string[], formatBookName: (name: string) => string }) {
|
function BookPage({ books, formatBookName, getBookFromUrl }: { books: string[], formatBookName: (name: string) => string, getBookFromUrl: (urlName: string) => string }) {
|
||||||
const { bookName } = useParams<{ bookName: string }>();
|
const { bookName } = useParams<{ bookName: string }>();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const actualBookName = bookName ? getBookFromUrl(bookName) : '';
|
||||||
|
|
||||||
const handleChapterSelect = (chapter: string) => {
|
const handleChapterSelect = (chapter: string) => {
|
||||||
navigate(`/book/${bookName}/chapter/${chapter}`);
|
navigate(`/book/${bookName}/chapter/${chapter}`);
|
||||||
};
|
};
|
||||||
@@ -34,13 +37,13 @@ function BookPage({ books, formatBookName }: { books: string[], formatBookName:
|
|||||||
navigate('/');
|
navigate('/');
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!bookName || !books.includes(bookName)) {
|
if (!bookName || !actualBookName || !books.includes(actualBookName)) {
|
||||||
return <div>Book not found</div>;
|
return <div>Book not found</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChapterSelector
|
<ChapterSelector
|
||||||
book={bookName}
|
book={actualBookName}
|
||||||
onChapterSelect={handleChapterSelect}
|
onChapterSelect={handleChapterSelect}
|
||||||
onBack={handleBack}
|
onBack={handleBack}
|
||||||
formatBookName={formatBookName}
|
formatBookName={formatBookName}
|
||||||
@@ -49,21 +52,23 @@ function BookPage({ books, formatBookName }: { books: string[], formatBookName:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Component for chapter reading page
|
// Component for chapter reading page
|
||||||
function ChapterPage({ formatBookName }: { formatBookName: (name: string) => string }) {
|
function ChapterPage({ formatBookName, getBookFromUrl }: { formatBookName: (name: string) => string, getBookFromUrl: (urlName: string) => string }) {
|
||||||
const { bookName, chapterNumber } = useParams<{ bookName: string, chapterNumber: string }>();
|
const { bookName, chapterNumber } = useParams<{ bookName: string, chapterNumber: string }>();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const actualBookName = bookName ? getBookFromUrl(bookName) : '';
|
||||||
|
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
navigate(`/book/${bookName}`);
|
navigate(`/book/${bookName}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!bookName || !chapterNumber) {
|
if (!bookName || !chapterNumber || !actualBookName) {
|
||||||
return <div>Chapter not found</div>;
|
return <div>Chapter not found</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BibleReader
|
<BibleReader
|
||||||
book={bookName}
|
book={actualBookName}
|
||||||
chapter={chapterNumber}
|
chapter={chapterNumber}
|
||||||
onBack={handleBack}
|
onBack={handleBack}
|
||||||
formatBookName={formatBookName}
|
formatBookName={formatBookName}
|
||||||
@@ -107,6 +112,26 @@ function App() {
|
|||||||
return bookName.replace(/^\d+_/, '').replace(/_/g, ' ');
|
return bookName.replace(/^\d+_/, '').replace(/_/g, ' ');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper function to convert display name back to file name
|
||||||
|
const getBookFileName = (displayName: string): string => {
|
||||||
|
// Find the book that matches the display name
|
||||||
|
const book = books.find(b => formatBookName(b) === displayName);
|
||||||
|
return book || displayName;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to convert book file name to URL-safe name
|
||||||
|
const getBookUrlName = (bookName: string): string => {
|
||||||
|
// Remove leading numbers and convert spaces to underscores for URL
|
||||||
|
return bookName.replace(/^\d+_/, '').replace(/ /g, '_');
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to convert URL name back to file name
|
||||||
|
const getBookFromUrl = (urlName: string): string => {
|
||||||
|
// Convert URL name back to display name, then find the file name
|
||||||
|
const displayName = urlName.replace(/_/g, ' ');
|
||||||
|
return getBookFileName(displayName);
|
||||||
|
};
|
||||||
|
|
||||||
const loadBooks = async () => {
|
const loadBooks = async () => {
|
||||||
try {
|
try {
|
||||||
console.log('Loading books from API...');
|
console.log('Loading books from API...');
|
||||||
@@ -218,9 +243,9 @@ function App() {
|
|||||||
{/* Main Content */}
|
{/* Main Content */}
|
||||||
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<HomePage books={books} formatBookName={formatBookName} />} />
|
<Route path="/" element={<HomePage books={books} formatBookName={formatBookName} getBookUrlName={getBookUrlName} />} />
|
||||||
<Route path="/book/:bookName" element={<BookPage books={books} formatBookName={formatBookName} />} />
|
<Route path="/book/:bookName" element={<BookPage books={books} formatBookName={formatBookName} getBookFromUrl={getBookFromUrl} />} />
|
||||||
<Route path="/book/:bookName/chapter/:chapterNumber" element={<ChapterPage formatBookName={formatBookName} />} />
|
<Route path="/book/:bookName/chapter/:chapterNumber" element={<ChapterPage formatBookName={formatBookName} getBookFromUrl={getBookFromUrl} />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user