- 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>
111 lines
3.0 KiB
TypeScript
111 lines
3.0 KiB
TypeScript
'use client'
|
|
|
|
import { Suspense, useState, useEffect } from 'react'
|
|
import dynamic from 'next/dynamic'
|
|
|
|
// Dynamic imports to avoid SSR issues with navigator/window
|
|
const OfflineBibleReader = dynamic(
|
|
() => import('@/components/bible/offline-bible-reader').then(mod => ({ default: mod.OfflineBibleReader })),
|
|
{ ssr: false, loading: () => <div>Loading offline reader...</div> }
|
|
)
|
|
|
|
const OfflineDownloadManager = dynamic(
|
|
() => import('@/components/bible/offline-download-manager').then(mod => ({ default: mod.OfflineDownloadManager })),
|
|
{ ssr: false, loading: () => <div>Loading download manager...</div> }
|
|
)
|
|
|
|
const InstallPrompt = dynamic(
|
|
() => import('@/components/pwa/install-prompt').then(mod => ({ default: mod.InstallPrompt })),
|
|
{ ssr: false }
|
|
)
|
|
import {
|
|
Box,
|
|
Container,
|
|
Typography,
|
|
Tabs,
|
|
Tab,
|
|
Paper
|
|
} from '@mui/material'
|
|
|
|
interface BibleVersion {
|
|
id: string
|
|
name: string
|
|
abbreviation: string
|
|
language: string
|
|
isDefault?: boolean
|
|
}
|
|
|
|
function OfflinePageContent() {
|
|
const [tabValue, setTabValue] = useState(0)
|
|
const [availableVersions, setAvailableVersions] = useState<BibleVersion[]>([])
|
|
|
|
useEffect(() => {
|
|
// Fetch available Bible versions for download
|
|
fetch('/api/bible/versions?all=true&limit=50')
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
if (data.success && data.versions) {
|
|
setAvailableVersions(data.versions)
|
|
}
|
|
})
|
|
.catch(err => console.error('Failed to fetch versions:', err))
|
|
}, [])
|
|
|
|
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
|
|
setTabValue(newValue)
|
|
}
|
|
|
|
return (
|
|
<Container maxWidth="lg" sx={{ py: 3 }}>
|
|
<Box sx={{ mb: 3 }}>
|
|
<Typography variant="h4" component="h1" gutterBottom>
|
|
Offline Bible Reading
|
|
</Typography>
|
|
<Typography variant="body1" color="text.secondary">
|
|
Download Bible versions for offline reading and access them without an internet connection.
|
|
</Typography>
|
|
</Box>
|
|
|
|
<Paper sx={{ mb: 3 }}>
|
|
<Tabs
|
|
value={tabValue}
|
|
onChange={handleTabChange}
|
|
variant="fullWidth"
|
|
sx={{ borderBottom: 1, borderColor: 'divider' }}
|
|
>
|
|
<Tab label="Offline Reader" />
|
|
<Tab label="Download Manager" />
|
|
</Tabs>
|
|
|
|
<Box sx={{ p: 0 }}>
|
|
{tabValue === 0 && (
|
|
<OfflineBibleReader
|
|
onRequestDownload={() => setTabValue(1)}
|
|
/>
|
|
)}
|
|
{tabValue === 1 && (
|
|
<OfflineDownloadManager
|
|
availableVersions={availableVersions}
|
|
onVersionDownloaded={() => setTabValue(0)}
|
|
/>
|
|
)}
|
|
</Box>
|
|
</Paper>
|
|
|
|
{/* PWA Install Prompt */}
|
|
<InstallPrompt autoShow={false} />
|
|
</Container>
|
|
)
|
|
}
|
|
|
|
export default function OfflinePage() {
|
|
return (
|
|
<Suspense fallback={
|
|
<Box sx={{ display: 'flex', justifyContent: 'center', p: 4 }}>
|
|
Loading offline reading interface...
|
|
</Box>
|
|
}>
|
|
<OfflinePageContent />
|
|
</Suspense>
|
|
)
|
|
} |