The core package can be used with React Native to create native chat experiences. This guide shows you how to implement chat functionality in your React Native app.

Setup with React Native

import { 
  createChat, 
  createConfig, 
  ApiCaller, 
  Platform,
  type MessageType 
} from '@opencx/widget';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { createContext, useContext, useState, useEffect } from 'react';

// Create chat context
const ChatContext = createContext<{
  messages: MessageType[];
  sendMessage: (content: string) => Promise<void>;
  loading: boolean;
  error: Error | null;
} | null>(null);

// Chat provider for React Native
export function ChatProvider({ children }: { children: React.ReactNode }) {
  const [messages, setMessages] = useState<MessageType[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);
  
  useEffect(() => {
    // Initialize chat with React Native specific platform
    const config = createConfig({
      token: 'YOUR_BOT_TOKEN',
      apiUrl: 'YOUR_API_URL',
      user: {
        email: "user@example.com",
        name: "User Name"
      }
    });

    const api = new ApiCaller({ config: config.getConfig() });

    // Platform configuration for React Native
    const platform: Platform = {
      env: { 
        platform: 'mobile',
        os: Platform.OS, // 'ios' or 'android'
      },
      // Use AsyncStorage for React Native
      storage: {
        getItem: async (key) => await AsyncStorage.getItem(key),
        setItem: async (key, value) => await AsyncStorage.setItem(key, value),
        removeItem: async (key) => await AsyncStorage.removeItem(key)
      },
      logger: {
        level: 'debug',
        prefix: '[OpenChat]',
        enabled: __DEV__ // Only enable logging in development
      }
    };

    const chat = createChat({ api, config, platform });

    const unsubscribe = chat.chatState.subscribe((state) => {
      setLoading(state.loading.isLoading);
      
      if (state.error.hasError) {
        setError(new Error(state.error.message));
        return;
      }
      
      setMessages(state.messages);
    });

    return () => {
      unsubscribe();
    };
  }, []);

  return (
    <ChatContext.Provider value={{
      messages,
      sendMessage: async (content) => {
        // Implementation of send message
      },
      loading,
      error
    }}>
      {children}
    </ChatContext.Provider>
  );
}

Component Examples

Chat Screen

import { View, StyleSheet, SafeAreaView } from 'react-native';

function ChatScreen() {
  const { messages, loading, error } = useChat();
  
  if (error) {
    return <ErrorView error={error} />;
  }

  return (
    <SafeAreaView style={styles.container}>
      {loading && <LoadingSpinner />}
      <MessageList messages={messages} />
      <InputBar />
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff'
  }
});

Message List

import { FlatList, ViewToken } from 'react-native';

function MessageList({ messages }: { messages: MessageType[] }) {
  const [viewableItems, setViewableItems] = useState<ViewToken[]>([]);
  
  const onViewableItemsChanged = useCallback(({ viewableItems }) => {
    setViewableItems(viewableItems);
  }, []);

  return (
    <FlatList
      data={messages}
      renderItem={({ item }) => (
        <MessageBubble message={item} />
      )}
      keyExtractor={(item, index) => `${index}-${item.id}`}
      onViewableItemsChanged={onViewableItemsChanged}
      viewabilityConfig={{
        itemVisiblePercentThreshold: 50
      }}
      inverted // Show latest messages at the bottom
      contentContainerStyle={styles.messageList}
    />
  );
}

Message Bubble

import { View, Text, Animated } from 'react-native';

function MessageBubble({ message }: { message: MessageType }) {
  const slideAnim = useRef(new Animated.Value(50)).current;
  const fadeAnim = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.parallel([
      Animated.spring(slideAnim, {
        toValue: 0,
        useNativeDriver: true
      }),
      Animated.timing(fadeAnim, {
        toValue: 1,
        duration: 200,
        useNativeDriver: true
      })
    ]).start();
  }, []);

  const isUser = message.type === 'FROM_USER';

  return (
    <Animated.View
      style={[
        styles.bubble,
        isUser ? styles.userBubble : styles.botBubble,
        {
          transform: [{ translateX: slideAnim }],
          opacity: fadeAnim
        }
      ]}
    >
      <Text style={styles.messageText}>
        {message.type === 'FROM_BOT' 
          ? (message as BotMessageType<{ text: string }>).data.text 
          : message.content
        }
      </Text>
    </Animated.View>
  );
}

Input Bar

import { TextInput, TouchableOpacity, Keyboard } from 'react-native';

function InputBar() {
  const { sendMessage } = useChat();
  const [input, setInput] = useState('');
  const [sending, setSending] = useState(false);

  const handleSend = async () => {
    if (!input.trim()) return;
    
    Keyboard.dismiss();
    setSending(true);
    try {
      await sendMessage(input);
      setInput('');
    } catch (error) {
      console.error('Failed to send message:', error);
    } finally {
      setSending(false);
    }
  };

  return (
    <View style={styles.inputContainer}>
      <TextInput
        style={styles.input}
        value={input}
        onChangeText={setInput}
        placeholder="Type a message..."
        editable={!sending}
        multiline
      />
      <TouchableOpacity
        onPress={handleSend}
        disabled={sending || !input.trim()}
        style={[styles.sendButton, sending && styles.sendButtonDisabled]}
      >
        <Text style={styles.sendButtonText}>
          {sending ? 'Sending...' : 'Send'}
        </Text>
      </TouchableOpacity>
    </View>
  );
}

Platform-Specific Features

Notifications

import PushNotificationIOS from '@react-native-community/push-notification-ios';
import messaging from '@react-native-firebase/messaging';

function useChatNotifications() {
  useEffect(() => {
    // Request permissions
    async function requestUserPermission() {
      const authStatus = await messaging().requestPermission();
      const enabled = 
        authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
        authStatus === messaging.AuthorizationStatus.PROVISIONAL;
        
      if (enabled) {
        const token = await messaging().getToken();
        // Send token to your server
      }
    }

    // Handle incoming messages
    const unsubscribe = messaging().onMessage(async remoteMessage => {
      // Handle foreground messages
      if (Platform.OS === 'ios') {
        PushNotificationIOS.addNotificationRequest({
          id: remoteMessage.messageId,
          body: remoteMessage.notification.body,
          title: remoteMessage.notification.title
        });
      }
    });

    requestUserPermission();
    return unsubscribe;
  }, []);
}

Storage

import EncryptedStorage from 'react-native-encrypted-storage';

// Secure storage implementation
const secureStorage = {
  getItem: async (key: string) => {
    try {
      return await EncryptedStorage.getItem(key);
    } catch (error) {
      console.error('Error reading secure storage:', error);
      return null;
    }
  },
  setItem: async (key: string, value: string) => {
    try {
      await EncryptedStorage.setItem(key, value);
    } catch (error) {
      console.error('Error writing to secure storage:', error);
    }
  },
  removeItem: async (key: string) => {
    try {
      await EncryptedStorage.removeItem(key);
    } catch (error) {
      console.error('Error removing from secure storage:', error);
    }
  }
};

Best Practices

  1. Performance

    • Use FlatList for message lists
    • Implement proper list item recycling
    • Optimize images and media
  2. Native Features

    • Handle keyboard properly
    • Support haptic feedback
    • Implement push notifications
  3. Platform Specifics

    • Follow platform design guidelines
    • Handle different screen sizes
    • Support both iOS and Android
  4. Offline Support

    • Implement message queuing
    • Handle reconnection gracefully
    • Cache important data
  5. Security

    • Use encrypted storage
    • Handle deep links safely
    • Implement proper authentication