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 // Debug logging
console.log('App component rendered'); 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(() => { useEffect(() => {
const urlParams = new URLSearchParams(location.search); const pathParts = location.pathname.split('/').filter(Boolean);
const versionParam = urlParams.get('version'); if (pathParts[0] === 'version' && (pathParts[1] === 'esv' || pathParts[1] === 'nkjv')) {
if (versionParam && (versionParam === 'esv' || versionParam === 'nkjv')) { setSelectedVersion(pathParts[1]);
setSelectedVersion(versionParam); } else if (location.pathname === '/') {
} else if (location.pathname === '/' && !urlParams.get('version')) { // At root path, no version is selected
// If we're at home without version param, clear selection
setSelectedVersion(''); setSelectedVersion('');
} }
}, [location.search]); }, [location.pathname]);
useEffect(() => { useEffect(() => {
console.log('App useEffect triggered'); console.log('App useEffect triggered');
@@ -56,14 +55,6 @@ function App() {
// Load versions when version changes // Load versions when version changes
useEffect(() => { useEffect(() => {
loadBooks(); 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 // Update page title to reflect selected version
const versionTitle = selectedVersion ? selectedVersion.toUpperCase() : ''; const versionTitle = selectedVersion ? selectedVersion.toUpperCase() : '';
@@ -252,32 +243,39 @@ function App() {
const getCurrentNavInfo = () => { const getCurrentNavInfo = () => {
const pathParts = location.pathname.split('/').filter(Boolean); 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 }; return { currentBook: null, currentChapter: null };
} }
if (pathParts[0] === 'book' && pathParts[1]) { const currentBook = pathParts[3]; // book name from /version/:versionId/book/:bookName
const currentBook = pathParts[1]; const currentChapter = pathParts[4] === 'chapter' && pathParts[5] ? pathParts[5] : null;
const currentChapter = pathParts[2] === 'chapter' && pathParts[3] ? pathParts[3] : null; return { currentBook, currentChapter };
return { currentBook, currentChapter };
}
return { currentBook: null, currentChapter: null };
}; };
const { currentBook, currentChapter } = getCurrentNavInfo(); const { currentBook, currentChapter } = getCurrentNavInfo();
// Component for the home page // Component for the version selection page (root)
const HomePage = () => { const VersionPage = () => {
const handleVersionSelect = (version: 'esv' | 'nkjv') => { const handleVersionSelect = (version: 'esv' | 'nkjv') => {
setSelectedVersion(version); navigate(`/version/${version}`);
setVersionSelected(true);
}; };
return (
<VersionSelector onVersionSelect={handleVersionSelect} />
);
};
// Component for book list page (version-specific)
const BookListPage = () => {
const { versionId } = useParams<{ versionId: string }>();
const handleBookSelect = (book: string) => { const handleBookSelect = (book: string) => {
const urlName = getBookUrlName(book); const urlName = getBookUrlName(book);
const url = selectedVersion ? `/book/${urlName}?version=${selectedVersion}` : `/book/${urlName}`; navigate(`/version/${versionId}/book/${urlName}`);
navigate(url); };
const handleBack = () => {
navigate('/');
}; };
const handleFavoriteChange = () => { const handleFavoriteChange = () => {
@@ -285,14 +283,6 @@ function App() {
setUser((prev: any) => ({ ...prev })); 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 ( return (
<BookSelector <BookSelector
books={books} books={books}
@@ -306,15 +296,15 @@ function App() {
// Component for book chapters page // Component for book chapters page
const BookPage = () => { const BookPage = () => {
const { bookName } = useParams<{ bookName: string }>(); const { versionId, bookName } = useParams<{ versionId: string, bookName: string }>();
const actualBookName = bookName ? getBookFromUrl(bookName) : ''; const actualBookName = bookName ? getBookFromUrl(bookName) : '';
const handleChapterSelect = (chapter: string) => { const handleChapterSelect = (chapter: string) => {
navigate(`/book/${bookName}/chapter/${chapter}`); navigate(`/version/${versionId}/book/${bookName}/chapter/${chapter}`);
}; };
const handleBack = () => { const handleBack = () => {
navigate('/'); navigate(`/version/${versionId}`);
}; };
const handleFavoriteChange = () => { const handleFavoriteChange = () => {
@@ -340,11 +330,11 @@ function App() {
// Component for chapter reading page // Component for chapter reading page
const ChapterPage = () => { 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 actualBookName = bookName ? getBookFromUrl(bookName) : '';
const handleBack = () => { const handleBack = () => {
navigate(`/book/${bookName}`); navigate(`/version/${versionId}/book/${bookName}`);
}; };
const handleFavoriteChange = () => { const handleFavoriteChange = () => {
@@ -412,7 +402,7 @@ function App() {
{selectedVersion ? ( {selectedVersion ? (
<select <select
value={selectedVersion} 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" 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) => ( {availableVersions.map((version) => (
@@ -434,10 +424,7 @@ function App() {
{currentBook && ( {currentBook && (
<> <>
<button <button
onClick={() => { onClick={() => navigate(`/version/${selectedVersion}`)}
const url = selectedVersion ? `/?version=${selectedVersion}` : '/';
navigate(url);
}}
className="hover:text-blue-600 dark:hover:text-blue-400" className="hover:text-blue-600 dark:hover:text-blue-400"
> >
Books Books
@@ -450,10 +437,7 @@ function App() {
<> <>
<ChevronRight className="h-4 w-4" /> <ChevronRight className="h-4 w-4" />
<button <button
onClick={() => { onClick={() => navigate(`/version/${selectedVersion}/book/${currentBook}`)}
const url = selectedVersion ? `/book/${currentBook}?version=${selectedVersion}` : `/book/${currentBook}`;
navigate(url);
}}
className="hover:text-blue-600 dark:hover:text-blue-400" className="hover:text-blue-600 dark:hover:text-blue-400"
> >
Chapters Chapters
@@ -571,9 +555,10 @@ 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 />} /> <Route path="/" element={<VersionPage />} />
<Route path="/book/:bookName" element={<BookPage />} /> <Route path="/version/:versionId" element={<BookListPage />} />
<Route path="/book/:bookName/chapter/:chapterNumber" element={<ChapterPage />} /> <Route path="/version/:versionId/book/:bookName" element={<BookPage />} />
<Route path="/version/:versionId/book/:bookName/chapter/:chapterNumber" element={<ChapterPage />} />
<Route path="/search" element={ <Route path="/search" element={
<SearchComponent <SearchComponent
formatBookName={formatBookName} formatBookName={formatBookName}