Files
2d4956fe68 buliding new auth setup to remove race condition during login (#961)
* buliding new auth setup to remove race condition during login

* revert complex fix. Just add local is loaded property

* Apply suggestion from @bitcoinuser

Co-authored-by: bitcoinuser <bitcoinuser@users.noreply.github.com>

---------

Co-authored-by: bitcoinuser <bitcoinuser@users.noreply.github.com>
2026-06-24 18:21:37 -04:00

287 lines
8.2 KiB
JavaScript

import {
createContext,
useState,
useContext,
useEffect,
useMemo,
useCallback,
useRef,
} from 'react';
import { AppState, Dimensions, Platform } from 'react-native';
import { getBoltzSwapPairInformation } from '../app/functions/boltz/boltzSwapInfo';
import {
buildRootstockSubmarineLimits,
DEFAULT_ROOTSTOCK_SUBMARINE_PAIR,
} from '../app/functions/boltz/rootstock/swapLimits';
import * as Network from 'expo-network';
import { navigationRef } from '../navigation/navigationService';
import {
BACKGROUND_THRESHOLD_MS,
// FORCE_RESET_SPAARK_STATE_MS,
} from '../app/constants';
import { crashlyticsLogReport } from '../app/functions/crashlyticsLogs';
// Initiate context
const AppStatusManager = createContext(null);
const AppStatusProvider = ({ children }) => {
const [minMaxLiquidSwapAmounts, setMinMaxLiquidSwapAmounts] = useState({
min: 1000,
max: 25000000,
rsk: {
min: DEFAULT_ROOTSTOCK_SUBMARINE_PAIR.limits.minimal,
max: DEFAULT_ROOTSTOCK_SUBMARINE_PAIR.limits.maximal,
submarine: DEFAULT_ROOTSTOCK_SUBMARINE_PAIR,
},
});
const [isConnectedToTheInternet, setIsConnectedToTheInternet] =
useState(true);
const [didGetToHomepage, setDidGetToHomePage] = useState(false);
const [appState, setAppState] = useState(AppState.currentState);
const [isAppFocused, setIsAppFocused] = useState(true);
const [screenDimensions, setScreenDimensions] = useState(() =>
Dimensions.get('screen'),
);
const shouldResetStateRef = useRef(null);
// const lastConnectedTimeRef = useRef(null);
const timeInBackgroundRef = useRef(0);
const hasInitializedNavListener = useRef(false);
const hasInitializedBoltzData = useRef(false);
const hasInitializedNetworkMonitoring = useRef(null);
const toggleDidGetToHomepage = useCallback(newInfo => {
setDidGetToHomePage(newInfo);
}, []);
const toggleMinMaxLiquidSwapAmounts = useCallback(newInfo => {
setMinMaxLiquidSwapAmounts(prev => ({ ...prev, ...newInfo }));
}, []);
useEffect(() => {
const handleWindowSizeChange = newDimensions => {
console.log('Window size state changed to:', newDimensions.screen);
setScreenDimensions(newDimensions.screen);
};
Dimensions.addEventListener('change', handleWindowSizeChange);
}, []);
useEffect(() => {
const handleAppStateChange = nextAppState => {
console.log('App state changed to:', nextAppState);
if (nextAppState === 'background') {
shouldResetStateRef.current = false;
timeInBackgroundRef.current = Date.now();
} else if (nextAppState === 'active') {
const timeInBackground = timeInBackgroundRef.current
? Date.now() - timeInBackgroundRef.current
: 0;
// const timeSinceLastReset = lastConnectedTimeRef.current
// ? Date.now() - lastConnectedTimeRef.current
// : 0;
if (
timeInBackground > BACKGROUND_THRESHOLD_MS
// ||
// (timeSinceLastReset > FORCE_RESET_SPAARK_STATE_MS &&
// timeInBackground > 45 * 1000)
) {
setTimeout(() => {
toggleDidGetToHomepage(false);
}, 100);
shouldResetStateRef.current = true;
// lastConnectedTimeRef.current = null;
} else {
shouldResetStateRef.current = false;
}
timeInBackgroundRef.current = null;
}
setAppState(nextAppState);
};
const subscription = AppState.addEventListener(
'change',
handleAppStateChange,
);
return () => {
subscription?.remove();
};
}, []);
useEffect(() => {
if (Platform.OS === 'ios') {
setIsAppFocused(true);
return;
}
const handleFocus = () => {
console.log('Android AppState focus event');
setIsAppFocused(true);
};
const handleBlur = () => {
console.log('Android AppState blur event');
setIsAppFocused(false);
};
const focusListener = AppState.addEventListener('focus', handleFocus);
const blurListener = AppState.addEventListener('blur', handleBlur);
return () => {
focusListener?.remove();
blurListener?.remove();
};
}, []);
useEffect(() => {
if (appState !== 'active' || hasInitializedNavListener.current) {
if (appState !== 'active' && !hasInitializedNavListener.current) {
console.log('Skipping navigation listener setup - app not active');
}
return;
}
console.log('Setting up navigation listener - first time app is active');
hasInitializedNavListener.current = true;
const unsubscribe = navigationRef.addListener('state', () => {
const routes = navigationRef.getRootState().routes;
const routeNames = routes.map(item => item.name).join('|');
crashlyticsLogReport(routeNames);
console.log(
'Current navigation stack',
navigationRef.getRootState().routes,
);
});
return () => {
unsubscribe();
};
}, [appState]);
useEffect(() => {
if (appState !== 'active' || hasInitializedBoltzData.current) {
if (appState !== 'active' && !hasInitializedBoltzData.current) {
console.log('Skipping Boltz API calls - app not active');
}
return;
}
console.log('Making Boltz API calls - first time app is active');
hasInitializedBoltzData.current = true;
(async () => {
try {
const [submarineSwapStats, reverseSwapStats] = await Promise.all([
getBoltzSwapPairInformation('submarine'),
getBoltzSwapPairInformation('reverse'),
]);
const liquidReverse = reverseSwapStats?.BTC?.['L-BTC'];
const min = liquidReverse?.limits?.minimal || 1000;
const max = liquidReverse?.limits?.maximal || 25000000;
setMinMaxLiquidSwapAmounts(prev => ({
// reverseSwapStats: liquidReverse,
// submarineSwapStats: submarineSwapStats['L-BTC'].BTC,
...prev,
min,
max,
rsk: buildRootstockSubmarineLimits(submarineSwapStats, prev.rsk),
}));
} catch (error) {
console.error('Error fetching Boltz swap information:', error);
}
})();
}, [appState]);
useEffect(() => {
if (appState !== 'active') {
console.log('Stopping network monitoring - app not active');
if (hasInitializedNetworkMonitoring.current) {
clearInterval(hasInitializedNetworkMonitoring.current);
hasInitializedNetworkMonitoring.current = null;
}
return;
}
console.log('Setting up network monitoring');
const checkNetworkState = async () => {
try {
const networkState = await Network.getNetworkStateAsync();
console.log(networkState, 'network state in startup function');
setIsConnectedToTheInternet(networkState.isInternetReachable);
} catch (error) {
console.error('Error checking network state:', error);
}
};
checkNetworkState();
hasInitializedNetworkMonitoring.current = setInterval(
checkNetworkState,
5000,
);
return () => {
console.log('Cleaning up network monitoring');
if (hasInitializedNetworkMonitoring.current) {
clearInterval(hasInitializedNetworkMonitoring.current);
hasInitializedNetworkMonitoring.current = null;
}
};
}, [appState]);
console.log(minMaxLiquidSwapAmounts, 'min max liquid swap amounts');
const contextValue = useMemo(
() => ({
minMaxLiquidSwapAmounts,
toggleMinMaxLiquidSwapAmounts,
isConnectedToTheInternet,
didGetToHomepage,
toggleDidGetToHomepage,
appState,
screenDimensions,
shouldResetStateRef,
isAppFocused,
// lastConnectedTimeRef,
}),
[
minMaxLiquidSwapAmounts,
toggleMinMaxLiquidSwapAmounts,
isConnectedToTheInternet,
didGetToHomepage,
toggleDidGetToHomepage,
appState,
screenDimensions,
shouldResetStateRef,
isAppFocused,
// lastConnectedTimeRef,
],
);
return (
<AppStatusManager.Provider value={contextValue}>
{children}
</AppStatusManager.Provider>
);
};
function useAppStatus() {
const context = useContext(AppStatusManager);
if (!context) {
throw new Error('useAppStatus must be used within a AppStatusProvider');
}
return context;
}
export { AppStatusManager, AppStatusProvider, useAppStatus };