Add buttons in Chat in React - createIT
Get a free advice now!

    Pick the topic
    Developer OutsourcingWeb developingApp developingDigital MarketingeCommerce systemseEntertainment systems

    Thank you for your message. It has been sent.

    Add buttons in Chat in React

    April 6, 2022
    Last update: April 4, 2024
    4 min read
    21
    0
    0
    Add buttons in Chat in React

    CHALLENGE: create a Chat message with clickable buttons

    SOLUTION: use the SendBird SDK and getSendUserMessage

    Nowadays, online presence is the key to a successful business. Handling Customer Support or answering frequently asked questions can be time consuming. A chat that can be embedded on a company website is a useful tool that can improve support answer time.

    Having a standard chat, we can receive and send messages. What about adding custom data to a message that will render action buttons? That way we can suggest some options to choose from the available list. We will focus on the frontend part (the widget).

    Building with SendBird

    SendBird, co-headquartered in Seoul, Korea, and San Mateo, California, has now raised around $221 million. Founded in 2013, SendBird offers chat API, which can be used to create Chats. In this tutorial, we will create a chat widget with message buttons.

    Chat widget

    The fastest way to start the chat will be to use the UIKit for React provided by Sendbird. It renders chat components that can be customized. We’re going to write a custom view for renderChatItem, where action buttons with possible answers will be displayed. After a user clicks a button, the answer will be sent back to the chat. Also check how to optimize message rendering in SendBird chat.

    chat window with a conversation

    After installing the dependency:

    npm install sendbird-uikit

    We can prepare the main app view. Make sure to change the APP_ID, USER_ID and CHANNEL_URL.

    // App.js
    import React from 'react';
    import './App.css';
    import { Channel, SendBirdProvider } from "sendbird-uikit";
    import "sendbird-uikit/dist/index.css";
    import {MyCustomChatMessage} from "./MyCustomChatMessage";
    const APP_ID = "AAA";
    const USER_ID = "BBB";
    const CHANNEL_URL = "CCC";
    const App = () => (
        <SendBirdProvider appId={APP_ID} userId={USER_ID}>
          <div style={{ height: '500px' }}>
            <Channel
                channelUrl={CHANNEL_URL}
                renderChatItem={({ message, onDeleteMessage, onUpdateMessage }) => (
                    <MyCustomChatMessage
                        message={message}
                        onDeleteMessage={onDeleteMessage}
                        onUpdateMessage={onUpdateMessage}
                        channelUrl={CHANNEL_URL}
                    />
                )}
            />
          </div>
        </SendBirdProvider>
    );
    export default App;

    The custom message view will remember the button that was clicked. The state is stored in application memory, but it will be lost after browser reload. The user will see buttons in a message and the new message will be sent to the chat by clicking. Our function getParsedData() is parsing message.data to look for additional message information, such as buttons.

    // MyCustomChatMessage.jsx
    import React, {useState} from 'react';
    import {RenderButtons} from "./RenderButtons";
    export const MyCustomChatMessage = ({ message, onDeleteMessage, onUpdateMessage, channelUrl }) => {
        const safelyParseJSON = (json) => {
            // This function cannot be optimised, it's best to
            // keep it small!
            var parsed;
            try {
                parsed = JSON.parse(json)
            } catch (e) {
                // Oh well, but whatever...
                return false;
            }
            return parsed // Could be undefined!
        }
        const getParsedData = () => {
            let data = "";
            if(message.messageType === 'file'){
                return data;
            }
            if(message.data !== 'undefined') {
                data = safelyParseJSON(message.data);
            }
            return data;
        }
        const [activeValue, setActiveValue] = useState( null );
        let msg_div_class = 'is-bot-msg';
        if(typeof(message.sender) !== 'undefined' && message.sender.nickname === 'Client'){
            msg_div_class = 'is-client-msg';
        }
        if(activeValue != null){
            msg_div_class += " is-action-taken";
        }
        return (
            <div className={msg_div_class}>
                <div className="msg-content">
                    {message.message}
                    <RenderButtons msgData={getParsedData()}  message={message} channelUrl={channelUrl} activeValue={activeValue} setActiveValue={setActiveValue} />
                </div>
            </div>
        );
    }

    Rendering buttons

    RenderButtons.jsx is expecting messages to have message.data defined and feature the msgButtons key. Example:

    “{\”msgButtons\”:[\”PAYMENTS\”, \”RETURNS\”, \”Other\”]}”;

    // RenderButtons.jsx
    import React, {useState, useEffect} from 'react';
    import SendMessageWithSendBird from "./SendMessage";
    export const RenderButtons = React.memo((props) => {
        const {msgData, message, channelUrl, activeValue, setActiveValue} = props;
        const keyName = 'msgButtons';
        const[buttonClicked, setButtonClicked] = useState(false);
        const [msgToSent, setMsgToSent] = useState({msg: "", activeValue: msgData.activeValue});
        const handleClick = (btn, index) => {
            setMsgToSent({msg: btn, activeValue: index});
        }
        useEffect(() => {
            if( typeof msgToSent.activeValue !== "undefined"){
                setActiveValue(msgToSent.activeValue);
            }
            return () => {
                setButtonClicked(true);
            };
            // eslint-disable-next-line
        }, [msgToSent]);
        let buttonsRaw = [];
        if(msgData[keyName] !== undefined){
            buttonsRaw = msgData[keyName];
        } else {
            return (
                <></>
            );
        }
        const component = !buttonClicked && msgToSent.msg ? (<SendMessageWithSendBird updateMsgData={{message: message, params: msgToSent.params3}} msg={msgToSent.msg} channelUrl={channelUrl} />) : (<></>);
        return (
            <>
                {buttonsRaw.length > 0 &&
                    <span className="d-flex">
                            {buttonsRaw.map((btn, index ) => (
                                <button key={index}  onClick={() => handleClick(btn, index)} type="button">{btn} {(activeValue === index) ? '✔' : '►'}</button>
                            ))}
                        {component}
                        </span>
                }
            </>
        )
    });

    SendBird Send Message

    We need SendMessageWithSendBird implementation to be able to send a message after a user clicks a button. Here is example source code:

    // SendMessage.jsx
    import React, { useEffect } from "react";
    import {
        withSendBird,
        sendBirdSelectors,
    } from "sendbird-uikit";
    import "sendbird-uikit/dist/index.css";
    const CustomComponent = (props) => {
        const {
            msg,
            channelUrl,
            extraData,
            sendMessage,
            sdk,
        } = props;
        const sendSelectTypeMessage = (msg, channelUrl, extraData = null) => {
            const params = new sdk.UserMessageParams();
            if(!msg){
                return;
            }
            params.message = msg;
            if(extraData){
                params.data = extraData;
            }
            sendMessage(channelUrl, params)
                .then(message => {
                })
                .catch(e => {
                    console.warn(e);
                });
        }
        useEffect(() => {
            sendSelectTypeMessage(msg, channelUrl, extraData);
        });
        return(
            <></>
        );
    };
    const SendMessageWithSendBird = withSendBird(CustomComponent, (state) => {
        const sendMessage = sendBirdSelectors.getSendUserMessage(state);
        const updateLastMessage = sendBirdSelectors.getUpdateUserMessage(state);
        const sdk = sendBirdSelectors.getSdk(state);
        return ({
            sendMessage,
            updateLastMessage,
            sdk
        });
    });
    export default SendMessageWithSendBird;

    How to debug messages

    A useful tip for debugging SendBird messages data is to use the UseEffect hook in the message component. On every view render, the developer console will show all parameters attached to the message.

    // MyCustomChatMessage.jsx
    import React, {useState, useEffect} from 'react'; 
    export const MyCustomChatMessage = ({ message, onDeleteMessage, onUpdateMessage, channelUrl }) => {
        useEffect(() => {
            // debug
            if(message.messageId){
                console.log(message);
            }
        }, [message]);
        // REST OF THE CODE
        (...)
        
    }
    Screenshot of colorful code

    Styling chat

    The last step is to add some basic styles, so our chat will not look so raw.

    /**
    index.css
     */
    .msg-content {
      display:inline-block;
      background:transparent;
      border-radius:5px;
      padding:6px 12px;
      margin:5px 0;
    }
    .msg-content button{
      cursor:pointer;
      display:inline-block;
      border:0;
      border-radius:5px;
      background:#333;
      color:#fff;
      padding:5px 10px;
      margin:5px 5px 5px 0;
    }
    .is-bot-msg {
      text-align:left;
    }
    .is-bot-msg .msg-content {
      background:#ccc;
    }
    .is-client-msg {
      text-align:right;
    }
    .is-client-msg .msg-content {
      background:orangered;
      color:#fff;
    }
    .d-flex {
      display:flex;
    }
    .is-action-taken {
      opacity:0.7;
      pointer-events: none;
      cursor:not-allowed;
    }

    Create ChatBOT

    We can use automation to optimize customer support. Having a BOT that can answer frequently asked questions and provide possible answers by rendering buttons can improve response time.

    Implementing BOTs is possible with SendBird. The first step will be to use the Platform API and to authenticate. The Webhook which is configured in panel settings will receive Client messages. Then, we can process it and send answers using the Bot Interface. More info available in the following tutorial provided by SendBird: https://sendbird.com/developer/tutorials/chatbot-google-dialogflow

    That’s it for today. Be sure to follow us for other tips and guidelines and don’t forget to sign up for our newsletter.

    Support – Tips and Tricks
    All tips in one place, and the database keeps growing. Stay up to date and optimize your work!

    Contact us