Mfereji React SDK Documentation

Welcome to the Mfereji React SDK documentation. This guide will help you get started with integrating the Mfereji SDK into your React application to enable chat functionalities.

Try Our Demo App

Experience the Mfereji SDK in action by visiting our demo app.

Open Demo App

Prerequisites

  • Sign Up on the Mfereji Dashboard: Go to the Mfereji Dashboard, sign up, and log in to your account and create your organisation. This step is part of theAPI Setup process.
  • Create an Application: Navigate to the 'Applications' section, create a new application, and obtain the App ID. This is also covered in theAPI Setup process.
  • Obtain a Chat API Token: Ensure your backend integrates with Mfereji's authentication mechanisms to generate and provide API tokens. Store the App ID and Chat API Token securely. Refer to theAPI Setup process for more details.

Installation

To install the Mfereji SDK, run one of the following commands:

To learn more about the SDK, visit the Mfereji SDK page.

npm install chatsasa-react-sdk
# or
yarn add chatsasa-react-sdk

Initialization

Initialize the Mfereji SDK in your application:

import Mfereji from 'chatsasa-react-sdk';

const chatSDK = new Mfereji({
  appId: 'YOUR_APP_ID',
  chatApiToken: 'YOUR_CHAT_API_TOKEN',
});

Usage

Here's how you can use various methods provided by the SDK:

Fetching User Profile

chatSDK.fetchUserProfile()
  .then(profile => console.log(profile))
  .catch(err => console.error(err));

Fetching All Channels

chatSDK.fetchAllChannels()
  .then(({ channels }) => console.log(channels))
  .catch(err => console.error(err));

Sending a Message

chatSDK.sendMessage(channelId, userId, 'Hello, World!')
  .then(message => console.log(message))
  .catch(err => console.error(err));

Fetching Messages

chatSDK.fetchMessages(channelId)
  .then(messages => console.log(messages))
  .catch(err => console.error(err));

Real-time Events

Connect to real-time service and subscribe to events:

chatSDK.connect();

chatSDK.on('new_message', (data) => {
  console.log('New message:', data);
});

chatSDK.on('typing', (data) => {
  console.log('Typing event:', data);
});

chatSDK.on('reaction', (data) => {
  console.log('Reaction event:', data);
});

// To unsubscribe from events
chatSDK.off('new_message', callback);

// Disconnect from real-time service
chatSDK.disconnect();

Example Application

Here's a basic example of how to use the SDK in a React component:

import React, { useEffect, useState } from "react";
import Mfereji from "chatsasa-react-sdk";

// Initialize Mfereji SDK with your app ID and API token
const chatSDK = new Mfereji({
  appId: 'YOUR_APP_ID',
  chatApiToken: 'YOUR_CHAT_API_TOKEN',
});

function App() {
  const [profile, setProfile] = useState(null);
  const [channels, setChannels] = useState([]);
  const [currentChannel, setCurrentChannel] = useState(null);
  const [messages, setMessages] = useState([]);
  const [messageText, setMessageText] = useState("");
  const [loading, setLoading] = useState(true);
  const [showModal, setShowModal] = useState(false);
  const [users, setUsers] = useState([]);
  const [selectedUser, setSelectedUser] = useState(null);
  const [newChatMessage, setNewChatMessage] = useState("");

  useEffect(() => {
    chatSDK.fetchUserProfile().then((response) => {
      if (response.user) {
        setProfile(response.user);
      } else {
        console.error("Error fetching user profile:", response.error);
      }
    });
  }, []);

  useEffect(() => {
    if (profile?.userId) {
      chatSDK.fetchAllChannels(profile.userId).then((response) => {
        if (response.channels) {
          setChannels(response.channels);
          setLoading(false);
        } else {
          console.error("Error fetching channels:", response.error);
        }
      });
    }
  }, [profile]);

  useEffect(() => {
    if (currentChannel) {
      chatSDK.fetchMessages(currentChannel.channelId).then((response) => {
        if (response.messages) {
          setMessages(response.messages);
        } else {
          console.error("Error fetching messages:", response.error);
        }
      });
    }
  }, [currentChannel]);

  useEffect(() => {
    if (showModal) {
      chatSDK
        .fetchUsers()
        .then((data) => setUsers(data.users))
        .catch((err) => console.error(err));
    }
  }, [showModal]);

  const handleSendMessage = () => {
    if (messageText.trim() !== "" && currentChannel && profile) {
      chatSDK
        .sendMessage(currentChannel.channelId, profile.userId, messageText)
        .then((response) => {
          if (response.message) {
            setMessages((prevMessages) => [...prevMessages, response.message]);
            setMessageText("");
          } else {
            console.error("Error sending message:", response.error);
          }
        })
        .catch((err) => console.error(err));
    }
  };

  const handleStartNewChat = () => {
    if (newChatMessage.trim() !== "" && selectedUser) {
      chatSDK
        .initiateChat(selectedUser.userId, profile.userId)
        .then((response) => {
          if (response.channel) {
            setChannels((prevChannels) => [...prevChannels, response.channel]);
            setCurrentChannel(response.channel);
            setMessages([{ message: newChatMessage, user: profile }]);
            setShowModal(false);
            setSelectedUser(null);
            setNewChatMessage("");
          } else {
            console.error("Error starting a new chat:", response.error);
          }
        });
    }
  };

  const getCounterpartyName = (channel) => {
    if (channel.channelUsers && channel.channelUsers.length > 0) {
      const counterparty = channel.channelUsers.find(
        (user) => user.userId !== profile?.userId
      );
      return counterparty
        ? `${counterparty.firstName} ${counterparty.lastName}`
        : "Unknown";
    }
    return "Unknown";
  };

  return (
    <div
      style={{
        fontFamily: "Arial",
        height: "100vh",
        display: "flex",
        flexDirection: "column",
      }}
    >
      <header
        style={{
          padding: "20px",
          backgroundColor: "#007bff",
          color: "white",
          textAlign: "center",
        }}
      >
        <h1>Simple Chat App</h1>
        {profile && (
          <h2>
            Welcome, {profile.firstName} {profile.lastName}
          </h2>
        )}
      </header>

      <div style={{ display: "flex", flexGrow: 1 }}>
        <div
          style={{
            width: "25%",
            borderRight: "1px solid #ddd",
            paddingRight: "10px",
            backgroundColor: "#f4f4f4",
            height: "100%",
          }}
        >
          <h3 style={{ padding: "10px" }}>Channels</h3>
          {loading ? (
            <div>Loading channels...</div>
          ) : channels.length > 0 ? (
            channels.map((channel) => (
              <div
                key={channel.channelId}
                onClick={() => setCurrentChannel(channel)}
                style={{
                  padding: "10px",
                  cursor: "pointer",
                  backgroundColor:
                    currentChannel?.channelId === channel.channelId
                      ? "#ddd"
                      : "white",
                  borderBottom: "1px solid #ccc",
                }}
              >
                {getCounterpartyName(channel)}
              </div>
            ))
          ) : (
            <div style={{ textAlign: "center", padding: "20px" }}>
              <p>No channels available.</p>
              <button
                onClick={() => setShowModal(true)}
                style={{
                  padding: "10px 20px",
                  backgroundColor: "#007bff",
                  color: "white",
                  border: "none",
                  borderRadius: "5px",
                  cursor: "pointer",
                }}
              >
                Start New Chat
              </button>
            </div>
          )}
        </div>

        <div
          style={{
            width: "75%",
            height: "100%",
            display: "flex",
            flexDirection: "column",
          }}
        >
          {currentChannel ? (
            <>
              <div
                style={{
                  padding: "20px",
                  backgroundColor: "#f1f1f1",
                  borderBottom: "1px solid #ddd",
                  display: "flex",
                  alignItems: "center",
                }}
              >
                <strong>{getCounterpartyName(currentChannel)}</strong>
              </div>
              <div
                style={{
                  flexGrow: 1,
                  overflowY: "scroll",
                  padding: "20px",
                  backgroundColor: "#ffffff",
                }}
              >
                {messages.map((msg, index) => (
                  <div key={index} style={{ marginBottom: "10px" }}>
                    <strong>{msg.user?.firstName || msg.userId}:</strong>{" "}
                    {msg.message}
                  </div>
                ))}
              </div>
              <div
                style={{
                  display: "flex",
                  padding: "10px 20px",
                  borderTop: "1px solid #ddd",
                  backgroundColor: "#f9f9f9",
                }}
              >
                <input
                  type="text"
                  value={messageText}
                  onChange={(e) => setMessageText(e.target.value)}
                  placeholder="Type your message..."
                  style={{
                    flexGrow: 1,
                    padding: "10px",
                    borderRadius: "5px",
                    border: "1px solid #ddd",
                    marginRight: "10px",
                  }}
                />
                <button
                  onClick={handleSendMessage}
                  style={{
                    padding: "10px 20px",
                    backgroundColor: "#28a745",
                    color: "white",
                    border: "none",
                    borderRadius: "5px",
                  }}
                >
                  Send
                </button>
              </div>
            </>
          ) : (
            <div style={{ textAlign: "center", padding: "50px" }}>
              <p>Select a channel to start messaging</p>
            </div>
          )}
        </div>
      </div>

      {showModal && (
        <div
          style={{
            position: "fixed",
            top: "0",
            left: "0",
            width: "100%",
            height: "100%",
            backgroundColor: "rgba(0, 0, 0, 0.5)",
            display: "flex",
            justifyContent: "center",
            alignItems: "center",
          }}
        >
          <div
            style={{
              backgroundColor: "white",
              padding: "20px",
              borderRadius: "5px",
              width: "400px",
              textAlign: "center",
            }}
          >
            <h3>Select a user to start a new chat</h3>
            {users.map((user) => (
              <div
                key={user.userId}
                style={{
                  padding: "10px",
                  cursor: "pointer",
                  borderBottom: "1px solid #ddd",
                }}
                onClick={() => setSelectedUser(user)}
              >
                {user.firstName} {user.lastName} - {user.userIdentifier}
              </div>
            ))}
            {selectedUser && (
              <div style={{ marginTop: "20px" }}>
                <input
                  type="text"
                  placeholder={`Message ${selectedUser.firstName}`}
                  value={newChatMessage}
                  onChange={(e) => setNewChatMessage(e.target.value)}
                  style={{
                    width: "80%",
                    padding: "10px",
                    borderRadius: "5px",
                    border: "1px solid #ddd",
                    marginBottom: "10px",
                  }}
                />
                <button
                  onClick={handleStartNewChat}
                  style={{
                    padding: "10px 20px",
                    backgroundColor: "#28a745",
                    color: "white",
                    border: "none",
                    borderRadius: "5px",
                  }}
                >
                  Start Chat
                </button>
              </div>
            )}
            <button
              onClick={() => setShowModal(false)}
              style={{
                marginTop: "10px",
                padding: "10px 20px",
                backgroundColor: "#dc3545",
                color: "white",
                border: "none",
                borderRadius: "5px",
                cursor: "pointer",
              }}
            >
              Close
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

export default App;