import React, { useEffect, Component, ErrorInfo, ReactNode } from 'react';
import { Provider as ReduxProvider, useDispatch } from 'react-redux';
import { PaperProvider } from 'react-native-paper';
import { QueryClientProvider } from '@tanstack/react-query';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import NetInfo from '@react-native-community/netinfo';
import { Alert, Text, View } from 'react-native';
import { store } from './store';
import { theme } from './theme';
import { queryClient } from './lib/queryClient';
import { RootNavigator } from './navigation/RootNavigator';
import { tokenStorage, userStorage } from './lib/storage';
import { setUser, setLoading, logout as logoutAction } from './store/slices/authSlice';
import { processOfflineQueue } from './hooks/useOfflineDraft';
import { proposalsApi, CreateProposalRequest } from './lib/api/proposals';
import { onSessionExpired } from './lib/api/client';
class ErrorBoundary extends Component<{ children: ReactNode }, { error: Error | null }> {
state = { error: null as Error | null };
static getDerivedStateFromError(error: Error) { return { error }; }
componentDidCatch(error: Error, info: ErrorInfo) {
console.error('ErrorBoundary caught:', error, info.componentStack);
}
render() {
if (this.state.error) {
return (
App Error
{this.state.error.message}
{this.state.error.stack?.slice(0, 500)}
);
}
return this.props.children;
}
}
function AuthBootstrap({ children }: { children: React.ReactNode }) {
const dispatch = useDispatch();
useEffect(() => {
(async () => {
try {
const tokens = await tokenStorage.get();
const user = await userStorage.get();
if (tokens && user && new Date(tokens.expiresAt) > new Date()) {
dispatch(setUser(user));
} else {
if (tokens) await tokenStorage.clear();
dispatch(setLoading(false));
}
} catch {
dispatch(setLoading(false));
}
})();
}, [dispatch]);
useEffect(() => {
return onSessionExpired(() => {
dispatch(logoutAction());
});
}, [dispatch]);
useEffect(() => {
const unsubscribe = NetInfo.addEventListener((state) => {
if (state.isConnected) {
processOfflineQueue((data) =>
proposalsApi.create(data as CreateProposalRequest),
)
.then((count) => {
if (count > 0) {
Alert.alert(
'Synced',
`${count} offline proposal${count > 1 ? 's' : ''} submitted.`,
);
}
})
.catch((err) => console.error('Offline queue sync failed:', err));
}
});
return unsubscribe;
}, []);
return <>{children}>;
}
export default function App() {
return (
);
}