Day 9: Adding Typing Indicators and Presence (Online/Offline) Status


Today, you’ll implement typing indicators to show when a user is typing and online/offline presence status to indicate user availability. These features enhance the real-time communication experience in the chat app.

What You Will Do Today:

  1. Use Firestore to track user presence.
  2. Display online/offline status for users.
  3. Add a typing indicator when users are typing.

Step 1: Track User Presence in Firestore

  1. Update Firestore Structure:
    • Create a new collection called users in Firestore.
    • Each document in the collection should have the following structure:
      • userId: String (the user’s unique ID).
      • isOnline: Boolean (whether the user is online).
      • lastSeen: Timestamp (the last time the user was online).
  2. Update User Presence in the App: Modify App.js to update the user’s presence status in Firestore.
import React, { useEffect } from 'react';
import auth from '@react-native-firebase/auth';
import firestore from '@react-native-firebase/firestore';

export default function App() {
  useEffect(() => {
    const user = auth().currentUser;

    if (user) {
      const userRef = firestore().collection('users').doc(user.uid);

      // Set user as online
      userRef.set({ isOnline: true }, { merge: true });

      // Set user as offline when the app is closed
      const handleOffline = async () => {
        await userRef.update({ isOnline: false, lastSeen: firestore.FieldValue.serverTimestamp() });
      };

      window.addEventListener('beforeunload', handleOffline);

      return () => {
        window.removeEventListener('beforeunload', handleOffline);
        handleOffline();
      };
    }
  }, []);

  return <YourNavigationStack />;
}

Step 2: Display User Online/Offline Status

  1. Add Presence UI to ChatScreen:
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import firestore from '@react-native-firebase/firestore';
import auth from '@react-native-firebase/auth';

function UserPresence({ userId }) {
  const [isOnline, setIsOnline] = useState(false);
  const [lastSeen, setLastSeen] = useState(null);

  useEffect(() => {
    const userRef = firestore().collection('users').doc(userId);

    const unsubscribe = userRef.onSnapshot((doc) => {
      if (doc.exists) {
        setIsOnline(doc.data().isOnline);
        setLastSeen(doc.data().lastSeen?.toDate());
      }
    });

    return unsubscribe;
  }, [userId]);

  return (
    <View style={styles.presenceContainer}>
      <Text style={styles.presenceText}>
        {isOnline ? 'Online' : `Last seen: ${lastSeen ? lastSeen.toLocaleString() : 'N/A'}`}
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  presenceContainer: {
    marginBottom: 10,
  },
  presenceText: {
    fontSize: 14,
    color: '#888',
  },
});

export default UserPresence;
  1. Use the UserPresence component in ChatScreen.js.
import UserPresence from '../components/UserPresence';

function ChatScreen() {
  const userId = auth().currentUser.uid;

  return (
    <View style={styles.container}>
      <UserPresence userId={userId} />
      {/* Chat UI */}
    </View>
  );
}

Step 3: Add Typing Indicator

  • Track Typing Status: Update Firestore with the user’s typing status.
const handleTyping = async (isTyping) => {
  const userId = auth().currentUser.uid;
  await firestore().collection('users').doc(userId).update({ isTyping });
};

Use this function in the text input:

<TextInput
  style={styles.input}
  placeholder="Type a message..."
  value={text}
  onChangeText={(value) => {
    setText(value);
    handleTyping(value.length > 0);
  }}
/>
  • Display Typing Indicator: Add a TypingIndicator component.
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import firestore from '@react-native-firebase/firestore';

function TypingIndicator({ userId }) {
  const [isTyping, setIsTyping] = useState(false);

  useEffect(() => {
    const userRef = firestore().collection('users').doc(userId);

    const unsubscribe = userRef.onSnapshot((doc) => {
      if (doc.exists) {
        setIsTyping(doc.data().isTyping);
      }
    });

    return unsubscribe;
  }, [userId]);

  if (!isTyping) return null;

  return (
    <View style={styles.typingIndicator}>
      <Text style={styles.typingText}>User is typing...</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  typingIndicator: {
    padding: 10,
    backgroundColor: '#f0f0f0',
    borderRadius: 8,
    alignSelf: 'flex-start',
    marginVertical: 5,
  },
  typingText: {
    fontSize: 14,
    fontStyle: 'italic',
    color: '#888',
  },
});

export default TypingIndicator;
  • Use the TypingIndicator component in ChatScreen.js.
<TypingIndicator userId={otherUserId} />

Step 4: Test Typing Indicators and Presence

  1. Run the app:
    • For Android: npx react-native run-android
    • For iOS: npx react-native run-ios.
  2. Verify online/offline status:
    • Open the app on multiple devices.
    • Confirm that user status updates in real-time.
  3. Test typing indicators:
    • Start typing in one device.
    • Verify that the “User is typing…” indicator appears on the other device.
See also  Queues and Background Jobs in Laravel: A Comprehensive Guide

Summary

Today, you added typing indicators and online/offline presence to the chat app. These features improve the real-time communication experience for users.

Tomorrow, you’ll wrap up by deploying and scaling the chat app.


Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.