// App.tsx

import React, { useState, useEffect } from 'react';
import { NavigationContainer, CommonActions } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { View, StyleSheet, Platform, TouchableOpacity, Keyboard } from 'react-native';
import HomeScreen from './src/screens/HomeScreen';
import ChatListScreen from './src/screens/ChatListScreen';
import ChatScreen from './src/screens/ChatScreen';
import { Ionicons } from '@expo/vector-icons';
import CustomText from './src/components/CustomText';
import { ChatProvider } from './src/context/ChatContext'; // Import ChatProvider

const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();

const ChatStack = () => (
  <Stack.Navigator
    initialRouteName="ChatList"
    screenOptions={{
      headerShown: false,
    }}
  >
    <Stack.Screen name="ChatList" component={ChatListScreen} />
    <Stack.Screen name="Chat" component={ChatScreen} />
  </Stack.Navigator>
);

const FiguresStack = () => (
  <Stack.Navigator
    initialRouteName="Home"
    screenOptions={{
      headerShown: false,
    }}
  >
    <Stack.Screen name="Home" component={HomeScreen} />
  </Stack.Navigator>
);

const TabBar = ({ state, descriptors, navigation }) => {
  const [isKeyboardVisible, setKeyboardVisible] = useState(false);

  useEffect(() => {
    const showSubscription = Keyboard.addListener('keyboardDidShow', () => {
      setKeyboardVisible(true);
    });
    const hideSubscription = Keyboard.addListener('keyboardDidHide', () => {
      setKeyboardVisible(false);
    });

    return () => {
      showSubscription.remove();
      hideSubscription.remove();
    };
  }, []);

  if (isKeyboardVisible) {
    return null; // Hide the TabBar when the keyboard is visible
  }

  return (
    <View style={styles.tabContainer}>
      {state.routes.map((route, index) => {
        const { options } = descriptors[route.key];
        const label =
          options.tabBarLabel !== undefined
            ? options.tabBarLabel
            : options.title !== undefined
            ? options.title
            : route.name;

        const isFocused = state.index === index;

        const onPress = () => {
          const event = navigation.emit({
            type: 'tabPress',
            target: route.key,
            canPreventDefault: true,
          });

          if (!isFocused && !event.defaultPrevented) {
            navigation.navigate(route.name);
          }
        };

        // Render the icon directly without extracting 'name'
        const icon = options.tabBarIcon
          ? options.tabBarIcon({
              focused: isFocused,
              color: isFocused ? '#007AFF' : '#8E8E93',
              size: 24,
            })
          : null;

        return (
          <TouchableOpacity
            key={route.key}
            accessibilityRole="button"
            accessibilityState={isFocused ? { selected: true } : {}}
            accessibilityLabel={options.tabBarAccessibilityLabel}
            testID={options.tabBarTestID}
            onPress={onPress}
            style={styles.tabItem}
          >
            {icon}
            <CustomText style={[styles.tabLabel, { color: isFocused ? '#007AFF' : '#8E8E93' }]}>
              {label}
            </CustomText>
          </TouchableOpacity>
        );
      })}
    </View>
  );
};

const App = () => {
  return (
    <ChatProvider> {/* Wrap NavigationContainer with ChatProvider */}
      <NavigationContainer>
        <Tab.Navigator
          initialRouteName="Figures"
          tabBar={(props) => <TabBar {...props} />}
          screenOptions={({ route }) => ({
            headerShown: false,
            tabBarIcon: ({ focused, color, size }) => {
              let iconName = '';
              if (route.name === 'Figures') {
                iconName = focused ? 'people' : 'people-outline';
              } else if (route.name === 'Chats') {
                iconName = focused ? 'chatbubbles' : 'chatbubbles-outline';
              }
              return <Ionicons name={iconName} size={size} color={color} />;
            },
          })}
        >
          <Tab.Screen
            name="Figures"
            component={FiguresStack}
            options={{
              tabBarLabel: 'Karakterler',
            }}
          />
          <Tab.Screen
            name="Chats"
            component={ChatStack}
            options={{
              tabBarLabel: 'Sohbetler',
            }}
            listeners={({ navigation, route }) => ({
              tabPress: e => {
                // Prevent default behavior
                e.preventDefault();

                // Reset the navigation stack to ChatList
                navigation.dispatch(
                  CommonActions.reset({
                    index: 0,
                    routes: [{ name: 'Chats', state: { routes: [{ name: 'ChatList' }] } }],
                  })
                );
              },
            })}
          />
        </Tab.Navigator>
      </NavigationContainer>
    </ChatProvider>
  );
};

const styles = StyleSheet.create({
  tabContainer: {
    flexDirection: 'row',
    backgroundColor: '#F8F8F8',
    borderTopWidth: 1,
    borderTopColor: '#E0E0E0',
    paddingBottom: Platform.OS === 'ios' ? 20 : 10,
    paddingTop: 10,
  },
  tabItem: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  tabLabel: {
    fontSize: 12,
    marginTop: 3,
    fontFamily: 'Poppins_400Regular',
  },
});

export default App;  // src/context/ChatContext.tsx

import React, { createContext, useState, useEffect, useCallback } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { Chat, Message } from '../types/types';

interface ChatWithLastMessage extends Chat {
  lastMessage?: string;
  lastMessageTimestamp?: number;
}

interface ChatContextProps {
  chats: ChatWithLastMessage[];
  addChat: (chat: Chat, message: Message) => Promise<void>;
  updateChat: (chatId: string, message: Message) => Promise<void>;
  deleteChat: (chatId: string) => Promise<void>;
  deleteAllChats: () => Promise<void>;
}

export const ChatContext = createContext<ChatContextProps>({
  chats: [],
  addChat: async () => {},
  updateChat: async () => {},
  deleteChat: async () => {},
  deleteAllChats: async () => {},
});

export const ChatProvider: React.FC = ({ children }) => {
  const [chats, setChats] = useState<ChatWithLastMessage[]>([]);

  // Load chats from AsyncStorage on mount
  useEffect(() => {
    const loadChats = async () => {
      try {
        const chatsData = await AsyncStorage.getItem('chats');
        const chatsList: Chat[] = chatsData ? JSON.parse(chatsData) : [];

        const chatsWithMessages: ChatWithLastMessage[] = await Promise.all(
          chatsList.map(async (chat) => {
            const messagesData = await AsyncStorage.getItem(`chat_${chat.id}_messages`);
            const messages: Message[] = messagesData ? JSON.parse(messagesData) : [];
            const lastMessage = messages[messages.length - 1]?.text || '';
            const lastTimestamp = messages[messages.length - 1]?.timestamp || chat.createdAt;
            return {
              ...chat,
              lastMessage,
              lastMessageTimestamp: lastTimestamp,
            };
          })
        );

        const sortedChats = chatsWithMessages.sort(
          (a, b) => (b.lastMessageTimestamp || 0) - (a.lastMessageTimestamp || 0)
        );

        setChats(sortedChats);
      } catch (error) {
        console.error('Error loading chats:', error);
      }
    };
    loadChats();
  }, []);

  // Add a new chat
  const addChat = useCallback(async (chat: Chat, message: Message) => {
    try {
      const newChat: ChatWithLastMessage = {
        ...chat,
        lastMessage: message.text,
        lastMessageTimestamp: message.timestamp,
      };
      const updatedChats = [...chats, newChat];
      setChats(updatedChats);
      await AsyncStorage.setItem('chats', JSON.stringify(updatedChats));
      await AsyncStorage.setItem(`chat_${chat.id}_messages`, JSON.stringify([message]));
    } catch (error) {
      console.error('Error adding chat:', error);
    }
  }, [chats]);

  // Update an existing chat with a new message
  const updateChat = useCallback(async (chatId: string, message: Message) => {
    try {
      // Retrieve existing messages
      const messagesData = await AsyncStorage.getItem(`chat_${chatId}_messages`);
      const messages: Message[] = messagesData ? JSON.parse(messagesData) : [];
      const updatedMessages = [...messages, message];
      await AsyncStorage.setItem(`chat_${chatId}_messages`, JSON.stringify(updatedMessages));

      // Update chat's last message and timestamp
      setChats((prevChats) => {
        const updatedChats = prevChats.map((chat) => {
          if (chat.id === chatId) {
            return {
              ...chat,
              lastMessage: message.text,
              lastMessageTimestamp: message.timestamp,
            };
          }
          return chat;
        }).sort((a, b) => (b.lastMessageTimestamp || 0) - (a.lastMessageTimestamp || 0));

        // Persist updated chats
        AsyncStorage.setItem('chats', JSON.stringify(updatedChats)).catch((err) =>
          console.error('Error updating chats in AsyncStorage:', err)
        );

        return updatedChats;
      });
    } catch (error) {
      console.error('Error updating chat:', error);
    }
  }, []);

  // Delete a specific chat
  const deleteChat = useCallback(async (chatId: string) => {
    try {
      const updatedChats = chats.filter((chat) => chat.id !== chatId);
      setChats(updatedChats);
      await AsyncStorage.setItem('chats', JSON.stringify(updatedChats));
      await AsyncStorage.removeItem(`chat_${chatId}_messages`);
    } catch (error) {
      console.error('Error deleting chat:', error);
    }
  }, [chats]);

  // Delete all chats
  const deleteAllChats = useCallback(async () => {
    try {
      setChats([]);
      await AsyncStorage.removeItem('chats');
      const keys = await AsyncStorage.getAllKeys();
      const chatMessageKeys = keys.filter(
        (key) => key.startsWith('chat_') && key.endsWith('_messages')
      );
      await AsyncStorage.multiRemove(chatMessageKeys);
    } catch (error) {
      console.error('Error deleting all chats:', error);
    }
  }, []);

  return (
    <ChatContext.Provider value={{ chats, addChat, updateChat, deleteChat, deleteAllChats }}>
      {children} {/* Ensure only children are rendered */}
    </ChatContext.Provider>
  );
};

ERROR  Warning: Error: Text strings must be rendered within a <Text> component.

This error is located at:
    in ChatProvider (created by App)
    in App (created by withDevTools(App))
    in withDevTools(App)
    in RCTView (created by View)
    in View (created by AppContainer)
    in RCTView (created by View)
    in View (created by AppContainer)
    in AppContainer
    in main(RootComponent), js engine: hermes


bu hatayı düzelt kodları eksiksiz geri yolla