import '@/styles/globals.css'
import type { AppProps } from 'next/app'
import { useI18n } from '@/hooks/useI18n'
import React from 'react'
import { platformSyncService } from '@/lib/platformSync'
import { nostrAuthService } from '@/lib/nostrAuth'
import { syncUserContentToCache } from '@/lib/userContentSync'
import { getLastSyncDate, getCurrentTimestamp } from '@/lib/syncStorage'
import { syncProgressManager } from '@/lib/syncProgressManager'
import { relaySessionManager } from '@/lib/relaySessionManager'
function I18nProvider({ children }: { children: React.ReactNode }): React.ReactElement {
// Get saved locale from localStorage or default to French
const getInitialLocale = (): 'fr' | 'en' => {
if (typeof window === 'undefined') {
return 'fr'
}
try {
const savedLocale = window.localStorage.getItem('zapwall-locale') as 'fr' | 'en' | null
if (savedLocale === 'fr' || savedLocale === 'en') {
return savedLocale
}
} catch {
// Fallback to browser locale detection
}
// Try to detect browser locale
const browserLocale = navigator.language.split('-')[0]
return browserLocale === 'en' ? 'en' : 'fr'
}
const [initialLocale, setInitialLocale] = React.useState<'fr' | 'en'>('fr')
const [localeLoaded, setLocaleLoaded] = React.useState(false)
React.useEffect(() => {
const locale = getInitialLocale()
setInitialLocale(locale)
setLocaleLoaded(true)
}, [])
const { loaded } = useI18n(initialLocale)
if (!localeLoaded || !loaded) {
return
Loading...
}
return <>{children}>
}
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()
}, [])
// Start platform sync on app mount and resume on each page navigation
React.useEffect(() => {
// Start continuous sync (runs periodically in background)
platformSyncService.startContinuousSync()
// Also trigger a sync on each page navigation
const handleRouteChange = (): void => {
if (!platformSyncService.isSyncing()) {
void platformSyncService.startSync()
}
}
// Listen to route changes
const router = require('next/router').default
router.events?.on('routeChangeComplete', handleRouteChange)
return () => {
router.events?.off('routeChangeComplete', handleRouteChange)
platformSyncService.stopSync()
}
}, [])
// Start user content sync on app mount if connected
React.useEffect(() => {
let syncInProgress = false
const startUserSync = async (): Promise => {
if (syncInProgress) {
return
}
const state = nostrAuthService.getState()
if (!state.connected || !state.pubkey) {
return
}
// Check if already recently synced (within last hour)
const storedLastSyncDate = await getLastSyncDate()
const currentTimestamp = getCurrentTimestamp()
const isRecentlySynced = storedLastSyncDate >= currentTimestamp - 3600
if (isRecentlySynced) {
console.log('[App] User content already synced recently, skipping')
return
}
syncInProgress = true
console.log('[App] Starting user content sync...')
try {
await syncUserContentToCache(state.pubkey, (progress) => {
syncProgressManager.setProgress(progress)
if (progress.completed) {
syncProgressManager.setProgress(null)
}
})
console.log('[App] User content sync completed')
syncProgressManager.setProgress(null)
} catch (error) {
console.error('[App] Error during user content sync:', error)
syncProgressManager.setProgress(null)
} finally {
syncInProgress = false
}
}
// Try to start sync immediately
void startUserSync()
// Also listen to connection changes to sync when user connects
const unsubscribe = nostrAuthService.subscribe((state) => {
if (state.connected && state.pubkey && !syncInProgress) {
void startUserSync()
}
})
return () => {
unsubscribe()
}
}, [])
return (
)
}