2026-01-13 14:49:19 +01:00

147 lines
4.2 KiB
TypeScript

import '@/styles/globals.css'
import type { AppProps } from 'next/app'
import Router from 'next/router'
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 {
useRelaySessionInitialization()
useServiceWorkerInitialization()
usePublishWorkerLifecycle()
usePlatformSyncOnNavigation()
useUserSyncOnNavigationAndAuth()
return (
<I18nProvider>
<Component {...pageProps} />
</I18nProvider>
)
}
function useRelaySessionInitialization(): void {
React.useEffect(() => {
void relaySessionManager.initialize()
}, [])
}
function useServiceWorkerInitialization(): void {
React.useEffect(() => {
if (typeof window !== 'undefined') {
void swSyncHandler.initialize()
}
}, [])
}
function usePublishWorkerLifecycle(): void {
React.useEffect(() => {
void publishWorker.start()
return () => {
void publishWorker.stop()
}
}, [])
}
function usePlatformSyncOnNavigation(): void {
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()
const handleRouteChange = (): void => {
void startPlatformSync()
}
Router.events?.on('routeChangeComplete', handleRouteChange)
return () => {
Router.events?.off('routeChangeComplete', handleRouteChange)
void swClient.stopPlatformSync()
}
}, [])
}
function useUserSyncOnNavigationAndAuth(): void {
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)
}
}
void startUserSync()
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()
}
}, [])
}