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:
@@ -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}
|
||||||
|
|||||||
Reference in New Issue
Block a user