Implement comprehensive PWA with offline Bible reading capabilities

- Add Web App Manifest with app metadata, icons, and installation support
- Create Service Worker with intelligent caching strategies for Bible content, static assets, and dynamic content
- Implement IndexedDB-based offline storage system for Bible versions, books, chapters, and verses
- Add offline download manager component for browsing and downloading Bible versions
- Create offline Bible reader component for seamless offline reading experience
- Integrate PWA install prompt with platform-specific instructions
- Add offline reading interface to existing Bible reader with download buttons
- Create dedicated offline page with tabbed interface for reading and downloading
- Add PWA and offline-related translations for English and Romanian locales
- Implement background sync for Bible downloads and cache management
- Add storage usage monitoring and management utilities
- Ensure SSR-safe implementation with dynamic imports for client-side components

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-28 22:20:44 +00:00
parent 83a981cabc
commit a01b2490dc
15 changed files with 2730 additions and 7 deletions

View File

@@ -4,6 +4,9 @@ import { useState, useEffect, useRef, useCallback } from 'react'
import { useTranslations, useLocale } from 'next-intl'
import { useAuth } from '@/hooks/use-auth'
import { useSearchParams, useRouter } from 'next/navigation'
import { OfflineDownloadManager } from '@/components/bible/offline-download-manager'
import { OfflineBibleReader } from '@/components/bible/offline-bible-reader'
import { InstallPrompt, useInstallPrompt } from '@/components/pwa/install-prompt'
import {
Box,
Typography,
@@ -69,7 +72,10 @@ import {
MenuBook,
Visibility,
Speed,
Chat
Chat,
CloudDownload,
WifiOff,
Storage
} from '@mui/icons-material'
interface BibleVerse {
@@ -149,6 +155,11 @@ export default function BibleReaderNew() {
const [showScrollTop, setShowScrollTop] = useState(false)
const [previousVerses, setPreviousVerses] = useState<BibleVerse[]>([]) // Keep previous content during loading
// Offline/PWA state
const [isOnline, setIsOnline] = useState(true)
const [isOfflineMode, setIsOfflineMode] = useState(false)
const [offlineDialogOpen, setOfflineDialogOpen] = useState(false)
// Bookmark state
const [isChapterBookmarked, setIsChapterBookmarked] = useState(false)
const [verseBookmarks, setVerseBookmarks] = useState<{[key: string]: any}>({})
@@ -177,6 +188,9 @@ export default function BibleReaderNew() {
const contentRef = useRef<HTMLDivElement>(null)
const verseRefs = useRef<{[key: number]: HTMLDivElement}>({})
// PWA install prompt
const { canInstall, isInstalled, showInstallPrompt } = useInstallPrompt()
// Load user preferences from localStorage
useEffect(() => {
const savedPrefs = localStorage.getItem('bibleReaderPreferences')
@@ -235,6 +249,39 @@ export default function BibleReaderNew() {
return () => window.removeEventListener('scroll', handleScroll)
}, [])
// Online/offline detection
useEffect(() => {
const handleOnline = () => {
setIsOnline(true)
if (isOfflineMode) {
// Show notification that connection is restored
console.log('Connection restored, you can now access all features')
}
}
const handleOffline = () => {
setIsOnline(false)
console.log('You are now offline. Only downloaded content is available.')
}
// Set initial state
setIsOnline(navigator.onLine)
// Check for offline mode preference
const offlineParam = new URLSearchParams(window.location.search).get('offline')
if (offlineParam === 'true') {
setIsOfflineMode(true)
}
window.addEventListener('online', handleOnline)
window.addEventListener('offline', handleOffline)
return () => {
window.removeEventListener('online', handleOnline)
window.removeEventListener('offline', handleOffline)
}
}, [isOfflineMode])
// Fetch versions based on showAllVersions state and locale
useEffect(() => {
setVersionsLoading(true)
@@ -1093,6 +1140,24 @@ export default function BibleReaderNew() {
<Share />
</IconButton>
</Tooltip>
<Tooltip title="Offline Downloads">
<IconButton
size="small"
onClick={() => setOfflineDialogOpen(true)}
sx={{ color: !isOnline ? 'warning.main' : 'inherit' }}
>
{isOnline ? <CloudDownload /> : <WifiOff />}
</IconButton>
</Tooltip>
{canInstall && !isInstalled && (
<Tooltip title="Install App">
<IconButton size="small" onClick={showInstallPrompt}>
<Storage />
</IconButton>
</Tooltip>
)}
</Box>
</Paper>
)
@@ -1386,6 +1451,38 @@ export default function BibleReaderNew() {
{/* Settings Dialog */}
{renderSettings()}
{/* Offline Downloads Dialog */}
<Dialog
open={offlineDialogOpen}
onClose={() => setOfflineDialogOpen(false)}
maxWidth="md"
fullWidth
fullScreen={isMobile}
>
<DialogTitle>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<Storage color="primary" />
Offline Bible Downloads
</Box>
</DialogTitle>
<DialogContent sx={{ p: 0 }}>
<OfflineDownloadManager
availableVersions={versions}
onVersionDownloaded={(versionId) => {
console.log(`Version ${versionId} downloaded successfully`)
}}
/>
</DialogContent>
<DialogActions>
<Button onClick={() => setOfflineDialogOpen(false)}>
Close
</Button>
</DialogActions>
</Dialog>
{/* PWA Install Prompt */}
<InstallPrompt autoShow={true} />
{/* Copy Feedback */}
<Snackbar
open={copyFeedback.open}