Day 7: Displaying Message Status (Sent, Delivered, Read)


Today, you’ll enhance the chat app by displaying message status indicators such as sent, delivered, and read. This feature improves user engagement and provides clarity on the status of each message.

What You Will Do Today:

  1. Add fields to Firestore to track message status.
  2. Update Firestore rules and structure for status management.
  3. Implement real-time status updates for sent, delivered, and read indicators.
  4. Display message statuses in the chat UI.

Step 1: Add Status Tracking to Firestore

  1. Each message document in the messages collection will now include:
    • status: String (sent, delivered, read).
  2. Update your Firebase Firestore structure:
    • Go to Firestore Database > Data.
    • Add a test message document with the status field.

Step 2: Update Firestore Rules for Status Management

Modify Firestore security rules to allow updates for the status field:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /messages/{messageId} {
      allow read: if request.auth != null;
      allow update: if request.auth != null && request.resource.data.status in ['delivered', 'read'];
      allow create: if request.auth != null;
    }
  }
}

Step 3: Set Message Status When Sent

  1. Update the sendMessage function in ChatScreen.js to initialize the message status as sent:
const sendMessage = async () => {
  if (text.trim()) {
    const { uid, email } = auth().currentUser;

    try {
      await firestore().collection('messages').add({
        text,
        userId: uid,
        userName: email,
        chatId,
        status: 'sent', // Initial status
        createdAt: firestore.FieldValue.serverTimestamp(),
      });
      setText('');
    } catch (error) {
      console.error('Error sending message:', error);
    }
  }
};

Step 4: Update Message Status to Delivered

  1. Use Firebase Functions to automatically update the status field to delivered when a message is added:
// functions/index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

exports.updateMessageStatusToDelivered = functions.firestore
  .document('messages/{messageId}')
  .onCreate(async (snapshot, context) => {
    const messageId = context.params.messageId;

    try {
      await admin.firestore().collection('messages').doc(messageId).update({
        status: 'delivered',
      });
      console.log('Message marked as delivered:', messageId);
    } catch (error) {
      console.error('Error updating message status to delivered:', error);
    }
  });
  1. Deploy the updated function: firebase deploy --only functions

Step 5: Update Message Status to Read

  1. In ChatScreen.js, update the fetchMessages function to mark messages as read when loaded:
useEffect(() => {
  const unsubscribe = firestore()
    .collection('messages')
    .where('chatId', '==', chatId)
    .orderBy('createdAt', 'desc')
    .onSnapshot(async (querySnapshot) => {
      const fetchedMessages = querySnapshot.docs.map((doc) => ({
        id: doc.id,
        ...doc.data(),
      }));

      setMessages(fetchedMessages);

      // Update status to 'read' for all fetched messages
      const batch = firestore().batch();
      querySnapshot.docs.forEach((doc) => {
        if (doc.data().status === 'delivered') {
          batch.update(doc.ref, { status: 'read' });
        }
      });
      await batch.commit();
    });

  return unsubscribe;
}, []);

Step 6: Display Message Status in the Chat UI

  1. Modify the renderMessage function to display the message status:
const renderMessage = ({ item }) => (
  <View style={styles.messageContainer}>
    <Text style={styles.messageUser}>{item.userName}</Text>
    <Text style={styles.messageText}>{item.text}</Text>
    <View style={styles.statusContainer}>
      <Text style={styles.messageTimestamp}>
        {item.createdAt?.toDate().toLocaleTimeString()}
      </Text>
      <Text style={styles.messageStatus}>
        {item.status === 'sent'
          ? '✓ Sent'
          : item.status === 'delivered'
          ? '✓✓ Delivered'
          : '✓✓ Read'}
      </Text>
    </View>
  </View>
);

const styles = StyleSheet.create({
  statusContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  messageStatus: {
    fontSize: 12,
    color: '#888',
    marginLeft: 8,
  },
});

Step 7: Test Message Status Updates

  1. Run the app:
    • For Android: npx react-native run-android
    • For iOS: npx react-native run-ios
  2. Send a message:
    • Confirm that the message status appears as ✓ Sent.
  3. Verify delivered and read statuses:
    • Open the chat on another device or simulator.
    • Confirm that the status updates to ✓✓ Delivered and then ✓✓ Read.
  4. Check Firestore:
    • Go to the Firebase Console under Firestore Database > messages.
    • Confirm that the status field updates correctly for each message.
See also  Advanced Form Handling with Alpine.js and Laravel

Summary

Today, you implemented message status indicators for sent, delivered, and read messages. This feature provides real-time feedback to users about their message statuses, enhancing the chat experience.

Tomorrow, you’ll work on handling attachments like images and videos.


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.