JIT
navigate to login screen on logout action
import React, {useState, useEffect, useCallback, useRef} from 'react'; import { CommonActions, NavigationContainer, useNavigationContainerRef, } from '@react-navigation/native'; import {createNativeStackNavigator} from '@react-navigation/native-stack'; import { ActivityIndicator, View, StyleSheet, Alert, Text, Dimensions, } from 'react-native'; import Toast from 'react-native-toast-message'; import {LogBox} from 'react-native'; // Contexts and Utils import AsyncStorageManager from '../utils/AsyncStorageManager'; // Adjust path if needed import {UserProvider, useUser} from '../context/UserContext'; // Adjust path if needed import { MqttProvider, useMqtt, MqttConnectionState, } from '../context/MqttContext'; // Adjust path if needed // Screens and Navigators import LoginScreen from '../screens/LoginScreen'; // Adjust path if needed import MainTabNavigator from './MainTabNavigator'; // Adjust path if needed import CommunityItemDetailScreen from '../screens/CommunityItemDetailScreen'; // <<< Import the detail screen import GalleryScreen from '../screens/GalleryScreen'; import FrontCameraScreen from '../screens/FrontCameraScreen'; import DeviceScreen from '../screens/DeviceScreen'; import ZoneScreen from '../screens/ZoneScreen'; import AlarmsScreen from '../screens/AlarmsScreen'; import DeviceItemScreen from '../screens/DeviceItemScreen'; import GiveAccessScreen from '../screens/GiveAccessScreen'; import ViewAccessScreen from '../screens/ViewAccessScreen'; // Notification Service import NotificationService, { ACTION_ACCEPT, ACTION_DECLINE, ACTION_SILENCE, } from '../services/NotificationService'; // Adjust path if needed import CCTVScreen from '../screens/CameraTabs/CCTVScreen'; import ZoneItemScreen from '../screens/ZoneItemScreen'; import AmenityScreen from '../screens/AmenityScreen'; import EventScreen from '../screens/EventScreen'; import CommunityScreen from '../screens/CommunityScreen'; import AmenityDetailsScreen from '../screens/AmenityDetailsScreen'; import EventDetailsScreen from '../screens/EventDetailsScreen'; import BookingScreen from '../screens/BookingTabs/BookingScreen'; const Stack = createNativeStackNavigator(); const {height: screenHeight} = Dimensions.get('window'); // --- Notification Handling Logic (Keep as before) --- const handleNotificationOpen = (navigationRef, data, action) => { console.log('Handling Notification Open/Action:', {data, action}); if (!data) { console.warn('No data found in notification to handle.'); return; } const targetScreen = data.screen; const notificationId = data.localNotificationId; // Assuming you pass this in userInfo // Example action handling (customize as needed) if (action) { console.log( `Action '${action}' taken on notification ID: ${notificationId}.`, ); // Handle specific actions like ACCEPT, DECLINE, SILENCE if (action === ACTION_ACCEPT) { console.log(`Handling ACCEPT action.`); // Navigate or perform accept logic if (targetScreen && navigationRef.isReady()) { navigationRef.navigate(targetScreen, { notificationData: data, actionTaken: action, }); } } else if (action === ACTION_DECLINE) { console.log(`Handling DECLINE action.`); // Perform decline logic } else if (action === ACTION_SILENCE) { console.log(`Handling SILENCE action.`); // Perform silence logic } // Optionally cancel the notification after handling the action // notificationService.current?.cancelNotificationById(notificationId); // Need access to service instance } else { // --- Notification Tapped --- console.log(`Handling TAP action for notification ID: ${notificationId}`); if (targetScreen && navigationRef.isReady()) { console.log(`Navigating to screen: ${targetScreen}`); // Ensure navigation happens correctly, potentially checking if already on the screen // or using reset/push depending on desired behavior. // Check if the target screen is the detail screen if (targetScreen === 'CommunityItemDetail') { // Ensure data contains the necessary 'item' for the detail screen if (data.item) { navigationRef.navigate(targetScreen, {item: data.item}); } else { console.warn( 'Notification tapped for CommunityItemDetail but missing item data.', ); // Optionally navigate to a default state or show an error } } else { // Handle navigation for other screens navigationRef.navigate(targetScreen, {notificationData: data}); } } else if (!targetScreen) { console.log('No target screen specified in notification data.'); } else { console.warn('Navigation not ready when notification was opened.'); // Optionally queue the navigation action until ready } } }; // --- Main Content Component --- const AppNavigationContent = () => { const [isLoading, setIsLoading] = useState(true); const [isLoggedIn, setIsLoggedIn] = useState(false); const [fcmToken, setFcmToken] = useState(null); const {setUserDetails, clearUserDetails, updateUserDetails} = useUser(); // Added updateUserDetails const { connect: connectMqtt, disconnect: disconnectMqtt, connectionState: mqttState, } = useMqtt(); const shownConnectedToastRef = useRef(false); const navigationRef = useNavigationContainerRef(); const notificationService = useRef(null); const [notificationInitialized, setNotificationInitialized] = useState(false); // Initialize Notification Service Ref (runs only once) useEffect(() => { LogBox.ignoreAllLogs(true); const onRegisterToken = token => { console.log('AppNavigator received FCM Token:', token); setFcmToken(token); // Store the token // TODO: Send the token to your backend server here if needed // if (token) { sendTokenToServer(token); } }; const onNotificationOpened = (data, action) => { // Ensure navigationRef is available and ready if needed handleNotificationOpen(navigationRef, data, action); }; console.log('AppNavigator: Creating NotificationService instance...'); // Pass the callbacks when creating the instance notificationService.current = new NotificationService( onNotificationOpened, onRegisterToken, ); // Don't initialize immediately here, wait for login status }, []); // Empty dependency array ensures this runs only once // Effect to initialize notifications AFTER login status is confirmed useEffect(() => { // Only initialize if logged in AND not already initialized if (isLoggedIn && notificationService.current && !notificationInitialized) { console.log( 'User logged in, initializing Notification Service (will request permissions)...', ); // Call initialize() which now includes requesting permissions notificationService.current .initialize() .then(() => { console.log('Notification Service initialization attempt complete.'); setNotificationInitialized(true); // Mark as initialized (or attempted) }) .catch(error => { console.error( 'Error during Notification Service initialization:', error, ); setNotificationInitialized(true); // Mark as initialized even on error to prevent retries }); } else if (!isLoggedIn && notificationInitialized) { // Optional: Reset initialization status if user logs out console.log( 'User logged out, resetting notification initialization status.', ); setNotificationInitialized(false); } }, [isLoggedIn, notificationInitialized]); // Depend on login status and initialization status // MQTT Connection Toast (Keep as before) useEffect(() => { if (mqttState === MqttConnectionState.CONNECTED) { if (!shownConnectedToastRef.current) { Toast.show({ type: 'success', text1: 'MQTT Status', text2: 'Successfully connected! 👋', position: 'bottom', visibilityTime: 3000, }); shownConnectedToastRef.current = true; } } else if ( mqttState !== MqttConnectionState.CONNECTING && mqttState !== MqttConnectionState.RECONNECTING ) { if (shownConnectedToastRef.current) { shownConnectedToastRef.current = false; } } }, [mqttState]); useEffect(() => { let isMounted = true; const checkLoginStatus = async () => { setIsLoading(true); // Start loading indicator try { const storedUserData = await AsyncStorageManager.getItem('userData'); console.log('isMounted', isMounted); console.log('storedUserData', storedUserData); if (isMounted) { if (storedUserData && storedUserData.token) { // Check only for token existence console.log('storedUserData after ismount', storedUserData); console.log('User session found.'); setUserDetails(storedUserData); setIsLoggedIn(true); } else { console.log('No user session found.'); setIsLoggedIn(false); clearUserDetails(); } } } catch (error) { console.error('AppNavigator: Failed to load user data:', error); if (isMounted) { Alert.alert('Error', 'Failed to load session data.'); setIsLoggedIn(false); clearUserDetails(); } } finally { if (isMounted) setIsLoading(false); // Session check complete } }; checkLoginStatus(); return () => { isMounted = false; }; }, [setUserDetails, clearUserDetails]); // Removed isLoggedIn from dependency array // Connect/Disconnect MQTT based on Login Status (Keep as before) useEffect(() => { if (isLoggedIn) { if ( mqttState === MqttConnectionState.DISCONNECTED || mqttState === MqttConnectionState.CLOSED || mqttState === MqttConnectionState.ERROR ) { console.log('User logged in, connecting MQTT...'); connectMqtt(); } } else { if ( mqttState === MqttConnectionState.CONNECTED || mqttState === MqttConnectionState.CONNECTING || mqttState === MqttConnectionState.RECONNECTING ) { console.log('User logged out, disconnecting MQTT...'); disconnectMqtt(); } } }, [isLoggedIn, connectMqtt, disconnectMqtt, mqttState]); // Login Handler (Keep as before) const handleLoginSuccess = useCallback( loggedInUserData => { setIsLoading(true); // Show loading briefly while setting state if (loggedInUserData && loggedInUserData.profileDetails) { setUserDetails(loggedInUserData); // Store the entire loggedInUserData setIsLoggedIn(true); // This will trigger the useEffect to initialize notifications // No need to call initialize here directly, the effect handles it } else { Alert.alert('Login Error', 'Failed to process login data.'); setIsLoggedIn(false); clearUserDetails(); } setIsLoading(false); }, [setUserDetails, clearUserDetails], ); // Logout Handler (Keep as before) const handleLogout = useCallback(async () => { try { await AsyncStorageManager.removeItem('userData'); } catch (error) { console.error('Logout Error clearing storage:', error); } finally { clearUserDetails(); // 👇 Update state first setIsLoggedIn(false); // 👇 Delay reset until after state change setTimeout(() => { navigationRef.current?.dispatch( CommonActions.reset({ index: 0, routes: [{ name: 'Login' }], }) ); }, 0); } }, [clearUserDetails]); // Loading State UI if (isLoading) { return ( <View style={styles.loadingContainer}> <ActivityIndicator size="large" color="#0000ff" /> <Text style={styles.loadingText}>Loading session...</Text> </View> ); } // Navigation Rendering return ( <NavigationContainer ref={navigationRef}> {/* The main stack navigator now includes Login, MainApp (Tabs), and the Detail screen */} <Stack.Navigator // Default screen options to apply to all screens screenOptions={{ headerStyle: {height: screenHeight * 0.07}, // <- Global header height is set here }}> {isLoggedIn ? ( <> <Stack.Screen name="MainApp" // This holds the Tab Navigator options={{headerShown: false}} // Hide header for the Tab container itself > {/* Pass onLogout to the component containing the logout button */} {props => <MainTabNavigator {...props} onLogout={handleLogout} />} </Stack.Screen> {/* Add CommunityItemDetailScreen HERE, outside MainApp but within the logged-in group */} <Stack.Screen name="CommunityItemDetail" component={CommunityItemDetailScreen} options={({route}) => ({ title: route.params?.item?.title || 'Item Details', headerShown: true, // <<< Make sure header is shown for the detail screen headerBackTitleVisible: false, // Optional: hide back button text on iOS })} /> <Stack.Screen name="GalleryScreen" component={GalleryScreen} options={({route}) => ({ title: route.params?.item?.title || 'Gallery', headerShown: true, // <<< Make sure header is shown for the detail screen headerBackTitleVisible: false, // Optional: hide back button text on iOS })} /> <Stack.Screen name="FrontCameraScreen" component={FrontCameraScreen} options={({route}) => ({ title: 'FRONT CAMERA', headerTitleAlign: 'center', // Add this line to center the title headerShown: true, headerBackTitleVisible: false, // Optional: hide back button text on iOS })} /> <Stack.Screen name="DeviceScreen" component={DeviceScreen} options={({route}) => ({ title: 'DEVICES', headerTitleAlign: 'center', // Add this line to center the title headerShown: true, headerBackTitleVisible: false, // Optional: hide back button text on iOS })} /> <Stack.Screen name="ZoneScreen" component={ZoneScreen} options={({route}) => ({ title: 'ZONES', headerTitleAlign: 'center', // Add this line to center the title headerShown: true, headerBackTitleVisible: false, // Optional: hide back button text on iOS })} /> <Stack.Screen name="AlarmsScreen" component={AlarmsScreen} options={({route}) => ({ title: 'ALARMS', headerTitleAlign: 'center', // Add this line to center the title headerShown: true, headerBackTitleVisible: false, // Optional: hide back button text on iOS })} /> <Stack.Screen name="CCTVScreen" component={CCTVScreen} options={({route}) => ({ title: 'CAMERAS', headerTitleAlign: 'center', // Add this line to center the title headerShown: true, headerBackTitleVisible: false, // Optional: hide back button text on iOS })} /> <Stack.Screen name="DeviceItemScreen" component={DeviceItemScreen} options={({route}) => ({ title: route.params?.device_name || 'DEVICES', headerTitleAlign: 'center', headerShown: true, headerBackTitleVisible: false, })} /> <Stack.Screen name="ZoneItemScreen" component={ZoneItemScreen} options={({route}) => ({ title: route.params?.zone_name || 'DEVICES', headerTitleAlign: 'center', headerShown: true, headerBackTitleVisible: false, })} /> <Stack.Screen name="GiveAccessScreen" component={GiveAccessScreen} options={({route}) => ({ title: 'ACCESS', headerTitleAlign: 'center', headerShown: true, headerBackTitleVisible: false, })} /> <Stack.Screen name="ViewAccessScreen" component={ViewAccessScreen} options={({route}) => ({ title: 'ACCESS', headerTitleAlign: 'center', headerShown: true, headerBackTitleVisible: false, })} /> <Stack.Screen name="AmenityScreen" component={AmenityScreen} options={({route}) => ({ title: 'AMENITIES', headerTitleAlign: 'center', headerShown: true, headerBackTitleVisible: false, })} /> <Stack.Screen name="EventScreen" component={EventScreen} options={({route}) => ({ title: 'EVENTS', headerTitleAlign: 'center', headerShown: true, headerBackTitleVisible: false, })} /> <Stack.Screen name="CommunityScreen" component={CommunityScreen} options={({route}) => ({ title: 'COMMUNITY', headerTitleAlign: 'center', headerShown: true, headerBackTitleVisible: false, })} /> <Stack.Screen name="AmenityDetailsScreen" component={AmenityDetailsScreen} options={({route}) => ({ title:'BOOKING', headerTitleAlign: 'center', headerShown: true, headerBackTitleVisible: false, })} /> <Stack.Screen name="EventDetailsScreen" component={EventDetailsScreen} options={({route}) => ({ title: 'BOOKING', headerTitleAlign: 'center', headerShown: true, headerBackTitleVisible: false, })} /> <Stack.Screen name="BookingScreen" component={BookingScreen} options={({route}) => ({ title: 'BOOKINGS', headerTitleAlign: 'center', headerShown: true, headerBackTitleVisible: false, })} /> {/* Add other globally accessible logged-in screens here (e.g., Settings, Profile) */} </> ) : ( // Logged-out screen(s) <Stack.Screen name="Login" options={{headerShown: false}} // Hide header for Login screen > {/* Pass fcmToken down to LoginScreen if needed for display/debug */} {props => ( <LoginScreen {...props} onLoginSuccess={handleLoginSuccess} fcmToken={fcmToken} /> )} </Stack.Screen> )} </Stack.Navigator> <Toast /> </NavigationContainer> ); }; // --- Main AppNavigator Component (Wraps Providers) --- const AppNavigator = () => { return ( <UserProvider> <MqttProvider> <AppNavigationContent /> </MqttProvider> </UserProvider> ); }; const styles = StyleSheet.create({ loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#f5f5f5', }, loadingText: {marginTop: 10, fontSize: 14, color: '#666'}, }); export default AppNavigator; import React from 'react'; import {Image, Dimensions} from 'react-native'; import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'; import HomeScreen from '../screens/tabs/HomeScreen'; import SceneScreen from '../screens/tabs/SceneScreen'; import ScheduleScreen from '../screens/tabs/ScheduleScreen'; import SettingsScreen from '../screens/tabs/SettingsScreen'; import {COLORS} from '../styles/colors'; import {HOME, SCENES, SCHEDULE, SETTINGS} from '../assets'; const Tab = createBottomTabNavigator(); const {height: screenHeight} = Dimensions.get('window'); const commonHeaderOptions = { headerTitleAlign: 'center', headerStyle: { backgroundColor: COLORS.status_bar_color, height: screenHeight * 0.07, }, headerTintColor: '#333', // Color of title and back button headerTitleStyle: { fontWeight: 'bold', fontSize: 18, }, }; const TabNavigator = ({onLogout}) => { return ( <Tab.Navigator screenOptions={({route}) => ({ ...commonHeaderOptions, // Apply common header styles to all tab screens tabBarIcon: ({focused, color, size}) => { let iconName; let iconColor = color; // Default icon color if (route.name === 'Home') { iconName = focused ? HOME : HOME; if (focused) { iconColor = 'red'; // Change color to red when Home is focused } } else if (route.name === 'Scene') { iconName = focused ? SCENES : SCENES; // Changed to layers icon } else if (route.name === 'Schedules') { iconName = focused ? SCHEDULE : SCHEDULE; // Changed to calendar icon } else if (route.name === 'Settings') { iconName = focused ? SETTINGS : SETTINGS; } // You can return any component that you like here! return ( <Image style={{ height: 25, width: 25, tintColor: focused && COLORS.red_color, }} source={iconName} /> ); }, tabBarActiveTintColor: COLORS.red_color, // Color for active tab (except Home when focused) tabBarInactiveTintColor: 'gray', // Color for inactive tabs tabBarStyle: { backgroundColor: '#ffffff', // Background color of the tab bar height: screenHeight * 0.08, // Increased height of the tab bar // borderTopWidth: 0, // Optional: remove top border // elevation: 5, // Optional: add shadow for Android }, tabBarLabelStyle: { fontSize: 12, marginBottom: 10, // Space below tab labels marginTop: 0, paddingBottom: 5, }, tabBarIconStyle: { marginTop: 3, // Adjust icon position }, })}> <Tab.Screen name="Home" component={HomeScreen} options={{title: 'Home', height: 20, backgroundColor: 'red'}} /> <Tab.Screen name="Scene" component={SceneScreen} options={{title: 'Scenes'}} /> <Tab.Screen name="Schedules" component={ScheduleScreen} options={{title: 'Schedules'}} /> {/* <Tab.Screen name="Settings" component={SettingsScreen} options={{title: 'Settings'}} /> */} <Tab.Screen name="Settings"> {props => <SettingsScreen {...props} onLogout={onLogout} />} </Tab.Screen> </Tab.Navigator> ); }; export default TabNavigator; import React from 'react'; import { View, Text, FlatList, StyleSheet, TouchableOpacity, Alert, } from 'react-native'; import {CommonActions} from '@react-navigation/native'; import {useUser, clearUserDetails} from '../../context/UserContext'; import ApiManager from '../../services/ApiManager'; import AsyncStorageManager from '../../utils/AsyncStorageManager'; const SettingsScreen = ({navigation}) => { const data = [ { id: '1', title: 'Notifications', description: 'Manage push notification preferences.', }, {id: '2', title: 'Account', description: 'Update your email or password.'}, {id: '3', title: 'Privacy', description: 'Read our Privacy Policy.'}, { id: '4', title: 'Terms of Service', description: 'Review the terms and conditions.', }, {id: '5', title: 'About', description: 'App version 1.0.0'}, {id: '6', title: 'Logout', description: 'Log out from app'}, ]; const {userDetails} = useUser(); console.log('userDetails', userDetails); const handleLogout = async () => { const email = userDetails.profileDetails?.email; const contactId = userDetails?.profileDetails?.contact_id; const societyId = userDetails?.profileDetails?.society_id; try { if (email && contactId && societyId) { await ApiManager.logout(email, contactId, societyId); console.log('Logout API call finished.'); } else { console.warn('Missing user details, skipping logout API call.'); } await AsyncStorageManager.removeItem('userData'); clearUserDetails(); setTimeout(() => { navigation.dispatch( CommonActions.reset({ index: 0, routes: [{name: 'Login'}], }), ); }, 50); } catch (error) { console.error('Logout failed:', error); Alert.alert('Logout Error', 'Something went wrong while logging out.'); } }; const handleLogoutPress = () => { Alert.alert( 'Logout', 'Are you sure you want to logout?', [ {text: 'Cancel', style: 'cancel'}, {text: 'OK', onPress: handleLogout}, ], {cancelable: true}, ); }; const renderItem = ({item}) => ( <TouchableOpacity onPress={() => { if (item.id == '6') { handleLogoutPress(); } }} style={styles.itemContainer}> <Text style={styles.itemText}>{item.title}</Text> {item.description && ( <Text style={styles.itemDescription}>{item.description}</Text> )} </TouchableOpacity> ); return ( <View style={styles.container}> <FlatList data={data} renderItem={renderItem} keyExtractor={item => item.id} ListEmptyComponent={<Text style={styles.emptyText}>No items yet.</Text>} contentContainerStyle={styles.listContentContainer} /> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', }, listContentContainer: { padding: 15, }, itemContainer: { backgroundColor: '#f9f9f9', padding: 18, marginVertical: 8, borderRadius: 8, borderWidth: 1, borderColor: '#eee', shadowColor: '#000', shadowOffset: {width: 0, height: 1}, shadowOpacity: 0.1, shadowRadius: 1.41, elevation: 2, }, itemText: { fontSize: 17, fontWeight: '500', color: '#333', }, itemDescription: { fontSize: 14, color: '#666', marginTop: 4, }, emptyText: { textAlign: 'center', marginTop: 50, fontSize: 16, color: '#888', }, }); export default SettingsScreen; on logout i want to go to login screen
Updated files
v1
what changes has done

The changes primarily involve centralizing the logout logic in AppNavigator.js and passing a logout handler down to SettingsScreen.js via MainTabNavigator.js.

Here's a summary:

  1. AppNavigator.js:

    • The handleLogout function was updated to directly manage the isLoggedIn state and trigger the navigation reset using CommonActions.reset immediately after clearing user data and setting isLoggedIn to false.
    • The setTimeout around the navigation reset was removed.
    • Added navigationRef to the dependency array of handleLogout.
    • Added a fallback navigation reset in the catch block of handleLogout to ensure navigation resets even if the API call fails.
    • The handleLogout function is passed as a prop to MainTabNavigator.
  2. MainTabNavigator.js:

    • The onLogout prop received from AppNavigator is now explicitly passed down to the SettingsScreen component.
  3. SettingsScreen.js:

    • Removed the internal handleLogout function, useUser hook, and imports for CommonActions, ApiManager, and AsyncStorageManager.
    • The handleLogoutPress function now calls the onLogout prop (passed from MainTabNavigator) when the user confirms the logout action in the alert.
    • Changed the comparison item.id == '6' to item.id === '6' for better practice.

This refactoring ensures that the navigation reset to the login screen is handled by the main navigator (AppNavigator) after the application state (isLoggedIn) is updated, providing a cleaner transition.*

Logout failed: [TypeError: Cannot read property 'profileDetails' of null]

The error TypeError: Cannot read property 'profileDetails' of null during logout indicates that the code is trying to access userDetails.profileDetails when userDetails is null or undefined.

Based on the previous code, this error likely occurs in the handleLogout function when attempting to access user details (like email, contactId, societyId) for the optional API call after clearUserDetails() has been called, or if userDetails was already null.

Although the API call lines were commented out in the AppNavigator.js code I provided, the error message suggests they might be active in your current setup, or there's a similar access happening elsewhere triggered by the logout sequence.

To make the handleLogout function more robust, especially if you intend to uncomment the API call later, you should access userDetails before clearing it.

Here are the updated files with the fix in AppNavigator.js to safely access userDetails and confirmation that SettingsScreen.js uses the passed onLogout prop.

Updated files
v2
Logout failed: [TypeError: Cannot read property 'profileDetails' of null] in AppNavigator
Updated files
v3
on logout need to call api in setting screen and go to LoginScreen const performLogoutSequence = async () => { setIsLoggingOut(true); const email = userDetails?.email; const contactId = userDetails?.contact_id; const societyId = userDetails?.society_id; if (!email || !contactId || !societyId) { Alert.alert( 'Logout Error', 'User data is incomplete, cannot perform server logout. Proceeding with client logout.', ); console.error( 'Logout API call skipped: Missing required user details in context.', {email, contactId, societyId}, ); } else { try { await ApiManager.logout(email, contactId, societyId); console.log('ProfileScreen: Logout API call finished.'); } catch (error) { console.error( 'ProfileScreen: Logout API call explicitly failed.', error, ); } } try { if (onLogout) { await onLogout(); } else { console.error('ProfileScreen: onLogout handler is missing!'); } navigation.reset({index: 0, routes: [{name: 'Login'}]}); } catch (clientLogoutError) { console.error( 'ProfileScreen: Client-side logout failed.', clientLogoutError, ); Alert.alert( 'Logout Error', 'Failed to clear local session. Please restart the app.', ); setIsLoggingOut(false); } }; const handleLogoutPress = () => { Alert.alert( 'Logout', 'Are you sure you want to logout?', [ { text: 'Cancel', style: 'cancel', onPress: () => setIsLoggingOut(false), }, {text: 'OK', onPress: performLogoutSequence}, ], {cancelable: true, onDismiss: () => setIsLoggingOut(false)}, ); };
Updated files
v4