fix: use SEO-friendly URLs for Read the Bible button

Changes:
- Load user's favorite Bible version or default to 'eng-asv'
- Convert book names to lowercase slugs for URLs
- Use path format: /{locale}/bible/{version}/{book}/{chapter}
- Replace spaces with hyphens in book names (e.g., "1 Corinthians" -> "1-corinthians")

Fixes issue where clicking "Read the Bible" button resulted in infinite loading
due to incorrect URL format with query parameters instead of path parameters.

Example URL: /en/bible/eng-asv/matthew/1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-13 06:16:45 +00:00
parent f96cd9231e
commit a0ed2b62ce

View File

@@ -86,6 +86,7 @@ export default function ReadingPlanDetailPage() {
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [plan, setPlan] = useState<UserPlan | null>(null) const [plan, setPlan] = useState<UserPlan | null>(null)
const [error, setError] = useState('') const [error, setError] = useState('')
const [bibleVersion, setBibleVersion] = useState('eng-asv') // Default Bible version
const [notesDialog, setNotesDialog] = useState<{ open: boolean; day: number; notes: string }>({ const [notesDialog, setNotesDialog] = useState<{ open: boolean; day: number; notes: string }>({
open: false, open: false,
day: 0, day: 0,
@@ -94,8 +95,28 @@ export default function ReadingPlanDetailPage() {
useEffect(() => { useEffect(() => {
loadPlan() loadPlan()
loadFavoriteVersion()
}, [params.id]) }, [params.id])
const loadFavoriteVersion = async () => {
try {
const token = localStorage.getItem('authToken')
if (!token) return
const response = await fetch('/api/user/favorite-version', {
headers: { 'Authorization': `Bearer ${token}` }
})
const data = await response.json()
if (data.version?.abbreviation) {
setBibleVersion(data.version.abbreviation.toLowerCase())
}
} catch (err) {
console.error('Error loading favorite version:', err)
// Keep default version
}
}
const loadPlan = async () => { const loadPlan = async () => {
setLoading(true) setLoading(true)
setError('') setError('')
@@ -400,14 +421,20 @@ export default function ReadingPlanDetailPage() {
{/* Read the Bible Button */} {/* Read the Bible Button */}
{plan.status === 'ACTIVE' && (() => { {plan.status === 'ACTIVE' && (() => {
const currentReading = getCurrentReading() const currentReading = getCurrentReading()
return currentReading ? ( if (!currentReading) return null
// Convert book name to lowercase slug for URL
const bookSlug = currentReading.book.toLowerCase().replace(/\s+/g, '-')
const bibleUrl = `/${locale}/bible/${bibleVersion}/${bookSlug}/${currentReading.chapter}`
return (
<Box sx={{ mb: 4, textAlign: 'center' }}> <Box sx={{ mb: 4, textAlign: 'center' }}>
<Button <Button
variant="contained" variant="contained"
size="large" size="large"
startIcon={<MenuBook />} startIcon={<MenuBook />}
component={Link} component={Link}
href={`/${locale}/bible?book=${encodeURIComponent(currentReading.book)}&chapter=${currentReading.chapter}`} href={bibleUrl}
sx={{ sx={{
py: 2, py: 2,
px: 4, px: 4,
@@ -426,7 +453,7 @@ export default function ReadingPlanDetailPage() {
Day {currentReading.day} of {duration} Day {currentReading.day} of {duration}
</Typography> </Typography>
</Box> </Box>
) : null )
})()} })()}
{/* Reading Schedule */} {/* Reading Schedule */}