Complete URL restructuring to use path-based version routing

Major changes:
- New URL structure: /version/esv/book/Genesis/chapter/1 instead of /book/Genesis/chapter/1?version=esv
- Version extracted from URL path instead of query parameters
- Component pages restructured: VersionPage, BookListPage, BookPage, ChapterPage
- Navigation updated throughout to use new path structure
- Routes updated to match new hierarchical structure
- Breadcrumb navigation fixed for new paths
- Version selector dropdown now navigates between versions

This eliminates query parameter state management issues and provides clean, RESTful URLs
This commit is contained in:
Ryderjj89
2025-09-28 15:15:31 -04:00
parent cbf1555668
commit f032016f43

View File

@@ -34,17 +34,16 @@ function App() {
// Debug logging
console.log('App component rendered');
// Read version from URL on mount and when location changes
// Extract version from URL path on mount and when location changes
useEffect(() => {
const urlParams = new URLSearchParams(location.search);
const versionParam = urlParams.get('version');
if (versionParam && (versionParam === 'esv' || versionParam === 'nkjv')) {
setSelectedVersion(versionParam);
} else if (location.pathname === '/' && !urlParams.get('version')) {
// If we're at home without version param, clear selection
const pathParts = location.pathname.split('/').filter(Boolean);
if (pathParts[0] === 'version' && (pathParts[1] === 'esv' || pathParts[1] === 'nkjv')) {
setSelectedVersion(pathParts[1]);
} else if (location.pathname === '/') {
// At root path, no version is selected
setSelectedVersion('');
}
}, [location.search]);
}, [location.pathname]);
useEffect(() => {
console.log('App useEffect triggered');
@@ -56,14 +55,6 @@ function App() {
// Load versions when version changes
useEffect(() => {
loadBooks();
// Update URL with version when it changes
const url = new URL(window.location.href);
if (selectedVersion) { // Add version parameter when selected
url.searchParams.set('version', selectedVersion);
} else {
url.searchParams.delete('version');
}
window.history.replaceState({}, '', url.toString());
// Update page title to reflect selected version
const versionTitle = selectedVersion ? selectedVersion.toUpperCase() : '';
@@ -252,32 +243,39 @@ function App() {
const getCurrentNavInfo = () => {
const pathParts = location.pathname.split('/').filter(Boolean);
if (pathParts.length === 0) {
if (pathParts.length < 3 || pathParts[0] !== 'version' || pathParts[2] !== 'book') {
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 currentBook = pathParts[3]; // book name from /version/:versionId/book/:bookName
const currentChapter = pathParts[4] === 'chapter' && pathParts[5] ? pathParts[5] : null;
return { currentBook, currentChapter };
};
const { currentBook, currentChapter } = getCurrentNavInfo();
// Component for the home page
const HomePage = () => {
// Component for the version selection page (root)
const VersionPage = () => {
const handleVersionSelect = (version: 'esv' | 'nkjv') => {
setSelectedVersion(version);
setVersionSelected(true);
navigate(`/version/${version}`);
};
return (
<VersionSelector onVersionSelect={handleVersionSelect} />
);
};
// Component for book list page (version-specific)
const BookListPage = () => {
const { versionId } = useParams<{ versionId: string }>();
const handleBookSelect = (book: string) => {
const urlName = getBookUrlName(book);
const url = selectedVersion ? `/book/${urlName}?version=${selectedVersion}` : `/book/${urlName}`;
navigate(url);
navigate(`/version/${versionId}/book/${urlName}`);
};
const handleBack = () => {
navigate('/');
};
const handleFavoriteChange = () => {
@@ -285,14 +283,6 @@ function App() {
setUser((prev: any) => ({ ...prev }));
};
// Show version selector if no version is selected
if (!selectedVersion) {
return (
<VersionSelector onVersionSelect={handleVersionSelect} />
);
}
// Show book selector once version is selected
return (
<BookSelector
books={books}
@@ -306,15 +296,15 @@ function App() {
// Component for book chapters page
const BookPage = () => {
const { bookName } = useParams<{ bookName: string }>();
const { versionId, bookName } = useParams<{ versionId: string, bookName: string }>();
const actualBookName = bookName ? getBookFromUrl(bookName) : '';
const handleChapterSelect = (chapter: string) => {
navigate(`/book/${bookName}/chapter/${chapter}`);
navigate(`/version/${versionId}/book/${bookName}/chapter/${chapter}`);
};
const handleBack = () => {
navigate('/');
navigate(`/version/${versionId}`);
};
const handleFavoriteChange = () => {
@@ -340,11 +330,11 @@ function App() {
// Component for chapter reading page
const ChapterPage = () => {
const { bookName, chapterNumber } = useParams<{ bookName: string, chapterNumber: string }>();
const { versionId, bookName, chapterNumber } = useParams<{ versionId: string, bookName: string, chapterNumber: string }>();
const actualBookName = bookName ? getBookFromUrl(bookName) : '';
const handleBack = () => {
navigate(`/book/${bookName}`);
navigate(`/version/${versionId}/book/${bookName}`);
};
const handleFavoriteChange = () => {
@@ -412,7 +402,7 @@ function App() {
{selectedVersion ? (
<select
value={selectedVersion}
onChange={(e) => setSelectedVersion(e.target.value)}
onChange={(e) => navigate(`/version/${e.target.value}`)}
className="text-xs text-gray-600 dark:text-gray-400 bg-transparent border-none focus:outline-none cursor-pointer hover:text-blue-600 dark:hover:text-blue-400"
>
{availableVersions.map((version) => (
@@ -434,10 +424,7 @@ function App() {
{currentBook && (
<>
<button
onClick={() => {
const url = selectedVersion ? `/?version=${selectedVersion}` : '/';
navigate(url);
}}
onClick={() => navigate(`/version/${selectedVersion}`)}
className="hover:text-blue-600 dark:hover:text-blue-400"
>
Books
@@ -450,10 +437,7 @@ function App() {
<>
<ChevronRight className="h-4 w-4" />
<button
onClick={() => {
const url = selectedVersion ? `/book/${currentBook}?version=${selectedVersion}` : `/book/${currentBook}`;
navigate(url);
}}
onClick={() => navigate(`/version/${selectedVersion}/book/${currentBook}`)}
className="hover:text-blue-600 dark:hover:text-blue-400"
>
Chapters
@@ -571,9 +555,10 @@ function App() {
{/* Main Content */}
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/book/:bookName" element={<BookPage />} />
<Route path="/book/:bookName/chapter/:chapterNumber" element={<ChapterPage />} />
<Route path="/" element={<VersionPage />} />
<Route path="/version/:versionId" element={<BookListPage />} />
<Route path="/version/:versionId/book/:bookName" element={<BookPage />} />
<Route path="/version/:versionId/book/:bookName/chapter/:chapterNumber" element={<ChapterPage />} />
<Route path="/search" element={
<SearchComponent
formatBookName={formatBookName}