151 lines
4.3 KiB
TypeScript
151 lines
4.3 KiB
TypeScript
import '@/styles/globals.css'
|
|
import type { AppProps } from 'next/app'
|
|
import { useI18n } from '@/hooks/useI18n'
|
|
import React from 'react'
|
|
import { nostrAuthService } from '@/lib/nostrAuth'
|
|
import { relaySessionManager } from '@/lib/relaySessionManager'
|
|
import { publishWorker } from '@/lib/publishWorker'
|
|
import { swSyncHandler } from '@/lib/swSyncHandler'
|
|
import { swClient } from '@/lib/swClient'
|
|
|
|
function I18nProvider({ children }: { children: React.ReactNode }): React.ReactElement {
|
|
const [initialLocale, setInitialLocale] = React.useState<'fr' | 'en'>('fr')
|
|
const [localeLoaded, setLocaleLoaded] = React.useState(false)
|
|
|
|
React.useEffect(() => {
|
|
const loadLocale = async (): Promise<void> => {
|
|
try {
|
|
// Migrate from localStorage if needed
|
|
const { localeStorage } = await import('@/lib/localeStorage')
|
|
await localeStorage.migrateFromLocalStorage()
|
|
|
|
// Load from IndexedDB
|
|
const savedLocale = await localeStorage.getLocale()
|
|
if (savedLocale) {
|
|
setInitialLocale(savedLocale)
|
|
setLocaleLoaded(true)
|
|
return
|
|
}
|
|
} catch {
|
|
// Fallback to browser locale detection
|
|
}
|
|
|
|
// Fallback: Try to detect browser locale
|
|
if (typeof window !== 'undefined') {
|
|
const browserLocale = navigator.language.split('-')[0]
|
|
setInitialLocale(browserLocale === 'en' ? 'en' : 'fr')
|
|
}
|
|
setLocaleLoaded(true)
|
|
}
|
|
|
|
void loadLocale()
|
|
}, [])
|
|
|
|
const { loaded } = useI18n(initialLocale)
|
|
|
|
if (!localeLoaded || !loaded) {
|
|
return <div className="min-h-screen bg-cyber-darker flex items-center justify-center text-neon-cyan">Loading...</div>
|
|
}
|
|
|
|
return children as React.ReactElement
|
|
}
|
|
|
|
export default function App({ Component, pageProps }: AppProps): React.ReactElement {
|
|
// Initialize relay session manager on app mount (reset all relays to active)
|
|
React.useEffect(() => {
|
|
void relaySessionManager.initialize()
|
|
}, [])
|
|
|
|
// Initialize Service Worker and sync handler
|
|
React.useEffect(() => {
|
|
if (typeof window !== 'undefined') {
|
|
void swSyncHandler.initialize()
|
|
}
|
|
}, [])
|
|
|
|
// Start publish worker on app mount to republish unpublished objects
|
|
React.useEffect(() => {
|
|
void publishWorker.start()
|
|
return () => {
|
|
void publishWorker.stop()
|
|
}
|
|
}, [])
|
|
|
|
// Start platform sync on app mount via Service Worker only
|
|
React.useEffect(() => {
|
|
const startPlatformSync = async (): Promise<void> => {
|
|
try {
|
|
const isReady = await swClient.isReady()
|
|
if (isReady) {
|
|
await swClient.startPlatformSync()
|
|
}
|
|
} catch (error) {
|
|
console.warn('[App] Service Worker not available for platform sync:', error)
|
|
}
|
|
}
|
|
|
|
void startPlatformSync()
|
|
|
|
// Trigger sync on each page navigation
|
|
const handleRouteChange = (): void => {
|
|
void startPlatformSync()
|
|
}
|
|
|
|
// Listen to route changes
|
|
const router = require('next/router').default
|
|
router.events?.on('routeChangeComplete', handleRouteChange)
|
|
|
|
return () => {
|
|
router.events?.off('routeChangeComplete', handleRouteChange)
|
|
void swClient.stopPlatformSync()
|
|
}
|
|
}, [])
|
|
|
|
// Start user content sync on app mount via Service Worker only
|
|
React.useEffect(() => {
|
|
const startUserSync = async (): Promise<void> => {
|
|
const state = nostrAuthService.getState()
|
|
if (!state.connected || !state.pubkey) {
|
|
return
|
|
}
|
|
|
|
try {
|
|
const isReady = await swClient.isReady()
|
|
if (isReady) {
|
|
await swClient.startUserSync(state.pubkey)
|
|
}
|
|
} catch (error) {
|
|
console.warn('[App] Service Worker not available for user content sync:', error)
|
|
}
|
|
}
|
|
|
|
// Try to start sync immediately
|
|
void startUserSync()
|
|
|
|
// Also listen to connection changes and route changes to sync when user connects or navigates
|
|
const router = require('next/router').default
|
|
const handleRouteChange = (): void => {
|
|
void startUserSync()
|
|
}
|
|
|
|
router.events?.on('routeChangeComplete', handleRouteChange)
|
|
|
|
const unsubscribe = nostrAuthService.subscribe((state) => {
|
|
if (state.connected && state.pubkey) {
|
|
void startUserSync()
|
|
}
|
|
})
|
|
|
|
return () => {
|
|
router.events?.off('routeChangeComplete', handleRouteChange)
|
|
unsubscribe()
|
|
}
|
|
}, [])
|
|
|
|
return (
|
|
<I18nProvider>
|
|
<Component {...pageProps} />
|
|
</I18nProvider>
|
|
)
|
|
}
|