@stackchat/proactive-messaging
TypeScript icon, indicating that this package has built-in type declarations

1.0.9 • Public • Published

@stackchat/proactive-messaging

A utility library for @stackchat/web-messenger to display proactive messages to a user above the Stackchat Web Messenger button or tab.

Table of Contents

Introduction

This library allows you to handle the creation, display and manipulation of messages that are proactively displayed to the user. A user can also interact with these messages eliminating the need of guesswork from the user.

Proactive messages can be triggered automatically during an ongoing conversation in the Stackchat Web Messenger or can be manually triggered as the need arises.

Each proactive message looks like this(when default styles are used)

Proactive Message

or like this with actions:

Proactive Message With Actions

Note: Proactive messages are only displayed if and only if the messenger widget is not open. If it is open, then all the proactive messages are silently ignored.

Usage

Note: This library works in conjuction with and requires @stackchat/web-messenger so as to be able to display proactive messages.

Script

If your project does not use a bundler or package manager, you can use our cdn hosted assets:

<!--
Copy and paste the following script right below
the 'script' tag for Stackchat Web Messenger
-->
<script async type="text/javascript" src="https://assets.au.stackchat.com/sdk/proactive-messaging/1.0.4/index.js"></script>

Optionally, if you would to include our default styles, also add the following:

<link type="text/css" src="https://assets.au.stackchat.com/sdk/proactive-messaging/1.0.4/main.css">

Now you have access to Stackchat Web Messenger(exposed as window.stackchat) and ProactiveMessaging(exposed as window.ProactiveMessaging)

<script>
	let messageStack;

	// add an event listener to initialise Proactive
	// Messaging once Stackchat Web Messenger has
	// finished initialising
	window.stackchat.on('ready', initialiseProactiveMessaging)

	window.stackchat.init({
		appId: "YOUR_APP_ID_HERE"
	})

	function initialiseProactiveMessaging() {
		// This step is required before calling
		// messageStack.start()
		messageStack = new window.ProactiveMessaging({
			messenger: window.stackchat,
			ttl: 4000 // default
			author: "Test Bot"
		})

		// start 
		messageStack.start();
	}
</script>

Package Manager

Install the dependencies via npm or yarn:

# NPM
npm install --save @stackchat/web-messenger@latest @stackchat/proactive-messaging@latest

# Yarn
yarn add @stackchat/web-messenger@latest @stackchat/proactive-messaging@latest

To include our default styles, also include the following:

import "@stackchat/proactive-messaging/dist/main.css"

Now in your JavaScript code:

import Stackchat from "@stackchat/web-messenger";
import { ProactiveMessaging } from "@stackchat/proactive-messaging";

let messageStack

// Add an event listener to know when Web Messenger 
// is ready to go
Stackchat.on('ready', initialiseProactiveMessaging)

//
const initialiseProactiveMessaging() => {
	// This step is required before calling
	// messageStack.start()
	messageStack = new ProactiveMessaging({
		messenger: Stackchat,
		ttl: 4000 // default
		author: "Test Bot"
	})

	// start 
	messageStack.start();
}

// Initialise Web Messenger
Stackchat.init({
	appId: "YOUR_APP_ID_HERE"
})

API

This library exposes a single class - ProactiveMessaging - which is used to handle proactives messages and to manipulate them.

const messageStack = new ProactiveMessaging(options) //see below

Initialisation Options

  • options

    Property Optional Default Value Description
    messenger No - An initialised instance of the StackChat Web Messenger. This is required to be able to display the proactive messages above the message bubble/tab
    ttl Yes 2000 The amount of time each message should live on the screen in milliseconds. By default, its 2s i.e. 2000ms
    author No - The name displayed at the top of each message. This is what will be used as author name for each proactive message
    maxMessages No - The maximum number of messages that are displayed on the screen at any given time. By default, it is 3
    singularCloseButton No - Determines whether to show one close button for all messages or one for each message

Methods

  • start()

    Triggers the ProactiveMessaging instance to start listening for incoming messages in a conversation. As long as the messenger widget is not open, ProactiveMessaging will ensure that any message which contains the following in its metadata property will be displayed proactively.

     {
     	proactive: true
     }
    
     // Therefore the message object should look like this
     message = {
     	metadata: {
     		proactive: true,
     		...otherMetaProps
     	},
     	...otherMessageProps
     }
  • addMessage(text, actions?)

    Allows the developer to simulate or display a proactive message to the user without it becoming a part of the ongoing conversation.

    For e.g.

     // Without actions
     messageStack.addMessage("Hello, world!")
     
     // With actions
     messageStack.addMessage(
     	"Hello, world!",
     	[
     		{
     			text: "Hello there!",
     			openMessengerOnReply: false
     		},
     		{
     			text: "Hi! What are you up to?",
     			openMessengerOnReply: true
     		}
     	]
     )
  • stop()

    Triggers the ProactiveMessaging instance to stop listening to incoming messages and removes all associated DOM elements from the page.

Event Binding

ProactiveMessaging offers two special methods to allow developers to react to events as they occur.

Note: You can add and remove event binding at any time.

  • on(event, handler)

    Allows you to specify a callback for a event which is called when that aforesaid event occurs.

  • off(event?, handler?)

    Allows you to remove a callback tied to an event. If no handler is specfied, it removes all the callbacks associated with the event. If no event has been specified, all callbacks for all events are cleared.

Events

This is the list of events that you can use with on and off methods as described above.

  • ready

    This event is fired when your ProactiveMessaging instance is ready. From this point on, it can start displaying proactive messages.

    messageStack.on("ready", () => {
      console.log("Proactive Messaging is ready!");
    });
  • proactive-message:clicked

    This event is fired when a user clicks on a proactive message. This event is not fired when a user dismisses a message or clicks on a quick reply.

    messageStack.on("proactive-message:clicked", (event) => {
      console.log("Proactive Message clicked > message", event.message);
    });
  • proactive-message:dismissed

    This event is fired when a user dismisses a proactive message. It is not fired if the message auto dismisses after the ttl.

    messageStack.on("proactive-message:dismissed", (event) => {
      console.log("Proactive Message dismissed > message", event.message);
    });
  • quick-reply:clicked

    This event is fired when a user clicks on one of the quick replies in a proactive message.

    messageStack.on("quick-reply:clicked", (event) => {
      console.log("Quick reply clicked");
      console.log("Message", event.message);
      console.log("Quick reply", event.quickReply);
    });
  • messenger:opened

    This event is fired whenever the Stackchat Web Messenger is opened by your ProactiveMessaging instance. Stackchat Web Messenger is opened when a user clicks on a message or clicks on one of the quick replies. Refer to the first part of the API section above.

    messageStack.on("messenger:opened", () => {
      console.log("Stackchat Web Messenger opened");
    });
  • clear

    This event is fired when all the proactive messages have been cleared - by user interaction or otherwise. Consider this as a blank slate similar to right after the ready event has occured.

    messageStack.on("clear", () => {
      console.log("All proactive messages cleared!");
    });

Styling

Default Styles

This library includes some base styles that display proactive messages in the nice UI as shown above here and here.

Consuming default styles depends on the way you integrate this library:

  • Script

    You can use our CDN hosted stylesheet via a script tag

     <link type="text/css" src="https://assets.au.stackchat.com/sdk/proactive-messaging/1.0.4/main.css">
  • Package Manager

    When using a package manager like npm or yarn, the default styles are automatically imported when you import ProactiveMessaging.

    In this case, you need only provide additional styles to suit your organisation's branding requirements. Please look at the custom styles section below.

Custom Styles

The module mostly uses classes to apply styles to the individual components and they are named logically so to enable easy overrides.

Important

Some base styles are required to display proactive messages properly. These styles are added to the elements inline and therefore, can not be overridden.


Animations

If you plan on overriding the default animation behaviour, please ensure you provide styles for two selectors i.e. @keyframes and @webkit-keyframes to account for compatibility with different browsers.


The default stylesheet is provided below for your reference. Use it as a reference point for classes you would like to add custom styles to.

/** The base container for all proactive messages **/
.proactive-container {
  overflow-y: hidden;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  flex-direction: column;
  z-index: 9998;
}

.proactive-container * {
	outline: none;
}

/** Singular close button to dismiss all messages **/
.proactive-container .external-close-button {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background-color: #d8d8d8;
  cursor: pointer;
}

/** The container for individual proactive message **/
.proactive-container .proactive-message {
	margin-bottom: 8px;
	padding: 4px;
}

/** The message inside each proactive message **/
.proactive-container .proactive-message .message {
  background-color: white;
  border-radius: 8px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  box-shadow: 0 0 4px 1px rgba(0, 0, 0, 0.2);
  width: 232px;
}

.proactive-container .proactive-message .message .header {
	position: relative;
	width: 100%;
	height: 40px;
	display: flex;
	align-items: center;
	justify-content: flex-start;
}

/** The author of the proactive message **/
.proactive-container .proactive-message .message .header .name {
	margin: 0;
	margin-left: 16px;
	margin-right: 8px;
	font-weight: 600;
	font-size: 14px;
	color: #8c1aff;
}

/** The close button inside each proactive message **/
.proactive-container .proactive-message .message .header .close-button {
	position: absolute;
	right: 0;
	top: 0;
	width: 40px;
	height: 100%;
	display: flex;
	align-items: center;
	justify-content: center;
	background-color: transparent;
	border: none;
	cursor: pointer;
}

/** The content of the proactive message **/
.proactive-container .proactive-message .message .content {
	padding: 8px 16px 16px 16px;
}

.proactive-container .proactive-message .message .content .text {
	margin: 0;
	font-size: 14px;
}

/** The container for quick actions(if any) for each individual message **/
.proactive-container .proactive-message .actions {
	margin-top: 4px;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: flex-end;
}

/** Each indidivual action of a proactive message **/
.proactive-container .proactive-message .actions .action {
	background: linear-gradient(
			0,
			rgba(140, 26, 255, 0.45) 60%,
			rgba(140, 26, 255, 0.45) 60%
		), linear-gradient(0, #fff 100%, #fff 0);
	box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
	border: 1px solid #8c1aff;
	border-radius: 4px;
	margin-left: 4px;
	font-size: 14px;
	padding: 11px;
	min-width: 64px;
	font-weight: 600;
	cursor: pointer;
	line-height: 16px;
	color: #000;
}

/**
 * Classes to handle animating in and out
 * of individual proactive messages
 */
.show-message,
.hide-message {
	-webkit-animation-name: animGenie;
	animation-name: animGenie;
	-webkit-animation-duration: 0.4s;
	animation-duration: 0.4s;
}

.hide-message {
	animation-direction: reverse;
	-webkit-animation-name: animGenieReverse;
	animation-name: animGenieReverse;
}

/**
 * The animation for messaging coming in
 * and being displayed on screen
 */
@-webkit-keyframes animGenie {
	0% {
		opacity: 0;
		-webkit-transform: translate3d(45%, calc(144%), 0) scale3d(0, 1, 1);
		transform: translate3d(45%, calc(144%), 0) scale3d(0, 1, 1);
		-webkit-animation-timing-function: ease-in;
		animation-timing-function: ease-in;
	}
	40% {
		opacity: 0.5;
		-webkit-transform: translate3d(27%, 0, 0) scale3d(0.02, 1.1, 1);
		transform: translate3d(27%, 0, 0) scale3d(0.02, 1.1, 1);
		-webkit-animation-timing-function: ease-out;
		animation-timing-function: ease-out;
	}
	70% {
		opacity: 0.6;
		-webkit-transform: translate3d(9%, -40px, 0) scale3d(0.8, 1.1, 1);
		transform: translate3d(9%, -40px, 0) scale3d(0.8, 1.1, 1);
	}
	100% {
		opacity: 1;
		-webkit-transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
		transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
	}
}

@keyframes animGenie {
	0% {
		opacity: 0;
		-webkit-transform: translate3d(45%, calc(144%), 0) scale3d(0, 1, 1);
		transform: translate3d(45%, calc(144%), 0) scale3d(0, 1, 1);
		-webkit-animation-timing-function: ease-in;
		animation-timing-function: ease-in;
	}
	40% {
		opacity: 0.5;
		-webkit-transform: translate3d(27%, 0, 0) scale3d(0.02, 1.1, 1);
		transform: translate3d(27%, 0, 0) scale3d(0.02, 1.1, 1);
		-webkit-animation-timing-function: ease-out;
		animation-timing-function: ease-out;
	}
	70% {
		opacity: 0.6;
		-webkit-transform: translate3d(9%, -40px, 0) scale3d(0.8, 1.1, 1);
		transform: translate3d(9%, -40px, 0) scale3d(0.8, 1.1, 1);
	}
	100% {
		opacity: 1;
		-webkit-transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
		transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
	}
}

/**
 * The animation for messaging going out
 * and being removed off screen
 */
@-webkit-keyframes animGenieReverse {
	0% {
		opacity: 0;
		-webkit-transform: translate3d(45%, calc(144%), 0) scale3d(0, 1, 1);
		transform: translate3d(45%, calc(144%), 0) scale3d(0, 1, 1);
		-webkit-animation-timing-function: ease-in;
		animation-timing-function: ease-in;
	}
	40% {
		opacity: 0.5;
		-webkit-transform: translate3d(27%, 0, 0) scale3d(0.02, 1.1, 1);
		transform: translate3d(27%, 0, 0) scale3d(0.02, 1.1, 1);
		-webkit-animation-timing-function: ease-out;
		animation-timing-function: ease-out;
	}
	70% {
		opacity: 0.6;
		-webkit-transform: translate3d(9%, -40px, 0) scale3d(0.8, 1.1, 1);
		transform: translate3d(9%, -40px, 0) scale3d(0.8, 1.1, 1);
	}
	100% {
		opacity: 1;
		-webkit-transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
		transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
	}
}

@keyframes animGenieReverse {
	0% {
		opacity: 0;
		-webkit-transform: translate3d(45%, calc(144%), 0) scale3d(0, 1, 1);
		transform: translate3d(45%, calc(144%), 0) scale3d(0, 1, 1);
		-webkit-animation-timing-function: ease-in;
		animation-timing-function: ease-in;
	}
	40% {
		opacity: 0.5;
		-webkit-transform: translate3d(27%, 0, 0) scale3d(0.02, 1.1, 1);
		transform: translate3d(27%, 0, 0) scale3d(0.02, 1.1, 1);
		-webkit-animation-timing-function: ease-out;
		animation-timing-function: ease-out;
	}
	70% {
		opacity: 0.6;
		-webkit-transform: translate3d(9%, -40px, 0) scale3d(0.8, 1.1, 1);
		transform: translate3d(9%, -40px, 0) scale3d(0.8, 1.1, 1);
	}
	100% {
		opacity: 1;
		-webkit-transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
		transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
	}
}

Readme

Keywords

none

Package Sidebar

Install

npm i @stackchat/proactive-messaging

Weekly Downloads

33

Version

1.0.9

License

SEE LICENSE IN LICENSE

Unpacked Size

94 kB

Total Files

13

Last publish

Collaborators

  • mszu
  • marrobin