How to Receive Picture, Video and Link Type Responses from SUSI kik Bot

In this blog, I will explain how to receive picture, video and link messages from SUSI Kik bot. To do so we have to implement these types in our code.

We will start off by making SUSI kik bot first. Follow this tutorial to make SUSI Kik bot. Next, we will implement picture, video, and link type messages from our bot. To implement these message types we need chatID and username of a user who has sent the message to our bot. To get the username of user we will use the following code:

bot.onTextMessage((message) => {
    var chartID = message.chatId;
    var Username;
        .then((user) => {
            message.reply(`Hey ${user.username}!`);
            Username = user.username;

Now as we have got the chatID and username we will use these and post a request to to send pictures, video, and link type messages. To post these requests use below code.

1) Picture:

To send picture type message we will define the type to picture,  URL of the picture to be sent to user and username of the user that we got from the code above.{
   url: "",
   auth: {
       user: 'your-bot-name',
       pass: 'your-api-key'
   json: {
       "messages": [
           'chatId': chatID,
           'type': 'picture',
           'to': Username,
           'picUrl': answer

2) Video:

To send video type message we will define the type to video, URL of the video to be sent to the user and username of the user that we got from the code above. In this request, we can also set extra attributes like mute and autoplay.{
   url: "",
   auth: {
       user: 'your-bot-name',
       pass: 'your-api-key'
   json: {
     "messages": [
           "chatId": "chatID",
           "type": "video",
           "to": "laura",
           "videoUrl": "",
           "muted": true,
           "autoplay": true,
           "attribution": "camera"

3) Link:
To send link type message to the user we will define the type of link, URL to be sent to the user and username of the user that we got from the code above.{
   url: "",
   auth: {
       user: 'your-bot-name',
       pass: 'your-api-key'
   json: {
     "messages": [
           "chatId": "chatID",
           "type": "link",
           "to": "laura",
           "url": "url-to-send"

If you want to learn more about kik API refer to

Kik API reference:

Continue ReadingHow to Receive Picture, Video and Link Type Responses from SUSI kik Bot

Implementing Copyright API in Open Event Frontend

This article illustrates how the copyright details have been displayed in the Open Event Frontend project using the Open Event Orga API. The API endpoints which will be mainly focussing on for fetching the copyright details are:

GET /v1/event-copyright/{event_copyright_id}

The events have copyrights which give the creator of the event exclusive rights for its use and distribution. In the Open Event application, the copyright details can be seen on the public event page. The public event page contains the events details like description, venue, tickets, speakers, sponsors along with the copyright details and these details are present on the public/index route in the application. Apart from index route, we have multiple subroutes to display the detailed information of speakers, sessions and schedule. The one thing which remains common to all the public event pages is the copyright information. Most of the time the copyright details are event specific so they are nested within the event model so if we want to display them we need to fetch the event model first.

The code to fetch the event model looks like this:

model(params) {
return'event', params.event_id, { include: 'social-links, event-copyright' });

If we try to comprehend the code then we can see that ‘event-copyright’ details are included inside the model. The reason behind this is the fact that the copyright information is not specific to a particular route and is displayed on the all the public event pages. After fetching the copyright details the next step we need to perform is to display them on the event’s index page.

The code to display the copyright details looks like this:

{{#if model.event.copyright}}
  <div class="copyright">
    {{public/copyright-item copyright=model.event.copyright}}

In the first line, we have an if conditional statement which verifies whether the copyright data exists or not. If the data does not exist then the copyright class will not be visible on the page and if the model is not empty then it will be displayed with the help of model.event.copyright which is responsible for displaying the fetched data on the page.

If we see in the third line, we have called an another template ‘copyright-item’ which is responsible for how the data will look or in simpler words the UI of the copyright data.

The code which determines UI of the copyright details looks like this:

<img src="{{copyright.logoUrl}}" class="copyright-image" alt="{{copyright.licence}}">
<div class='copyright text'>
    {{t 'This event is licenced under'}} <a href="{{copyright.licenceUrl}}"> {{copyright.licence}} </a>.

In the first line of code, we are providing the src to the image which is stored in ‘logoUrl’ variable of the copyright object. If we hover the image we can see the copyright license which is stored in the ‘license’ variable. Then finally we have copyright license’s URL which is stored under ‘licenceUrl’ variable of copyright object. The resulting UI from the above source code looks like this :

Fig. 1: The user interface of the copyright details

Now we need to test whether the copyright details are completely displayed or not. To test it we created an integration test in which we created a sample ember object to check the correctness of the code. The sample ember object for copyright details looks like this:

To view the complete code regarding the copyright API integration check this.

const copyright = EmberObject.create({
  holder     : 'Creative Commons',
  holderUrl  : '',
  licence    : 'Public Domain Dedication (CC0)',
  licenceUrl : '',
  year       : 2007,
  logoUrl    : ''

To conclude, this is how we integrated copyright information inside the Open Event Frontend project using the Open Event Orga API efficiently.


Image Source :

Continue ReadingImplementing Copyright API in Open Event Frontend

Ember Mixins used in Open Event Frontend

This post will illustrate how ember mixins are used in the Open Event Frontend to avoid code duplication and to keep it clean to reduce code complexity.

The Open Event application needs forms at several places like at the time of login, for the creation of the event, taking the details of the user, creating discount codes for tickets etc. Every form performs similar actions which taking input and finally storing it in the database. In this process, a set of things keep executing in the background such as continuous form validation which means checking inputted values to ensure they are correctly matched with their type as provided in the validation rules, popping out an error message in case of wrong inputted values, etc. which is common to all the forms. The only thing which changes is the set of validation rules which are unique for every form. So let’s see how we solved this issue using Ember Mixins.

While writing the code, we often run into the situation where we need to use the similar behaviour in different parts of the project. We always try not to duplicate the code and keep finding the ways to DRY ( Don’t Repeat Yourself ) up the code. In Ember, we can share the code in the different parts of the project using Ember.Mixins.

While creating the forms, we mostly have differing templates but the component logic remains same. So we created a mixin form.js which contains all the properties which are common to all the forms. The code mixin contains can be reused throughout different parts of the application and is not a concern of any one route, controller, component, etc. The mixins don’t get instantiated until we pass them into some object, and they get created in the order of which they’re passed in. The code for form.js mixin looks like this.

export default Mixin.create({
  autoScrollToErrors : true,
  autoScrollSpeed    : 200,

  getForm() {
    return this.get('$form');

  onValid(callback) {
    this.getForm().form('validate form');
    if (this.getForm().form('is valid')) {
  didRender() {
      const $popUps = this.$('.has.popup');
      if ($popUps) {
          hoverable: true
      let $form = this.$('.ui.form');
      if ($form) {
        $form = $form.first();
        if (this.get('getValidationRules') && $form) {
          $form.form(merge(defaultFormRules, this.getValidationRules()));
  didInsertElement() {
    $ = (value, format = FORM_DATE_FORMAT) => {
      if (value && value.length > 0 && format) {
        return moment(value, format).isValid();
      return true;

The complete code can be seen here.

Let’s start understanding the above code. In the first line, we created a mixin via Ember.Mixin.create() method. We have then specified the property ‘autoScrollToErrors’ to true so in case if there is some error, the form will automatically scroll to the error. The property ‘autoScrollSpeed’ specifies the speed with which the form will auto scroll to show the error. ‘getForm()’ method helps in getting the object which will be passed to the mixin. In ‘onValid()’ method we’re validating the form and passing the callbacks if it is correctly validated. We then have ‘didRender()’ method which renders the popups, checkboxes and form rules. The popups help in showing the errors on the form. In this method, we’re fetching the validation rules which are written in child/subclasses which are using this mixin to create the form.  The validation rules help in validating the form and tells if the value inputted is correct or not. In most of the forms, we have a field which asks for some specific date. The piece of code under ‘didInsertElement()’ helps in validating the date and returns true if it is correct. We have ‘willDestroyElement()’ method which destroys the popup if the window is changed/refreshed.

Let see the use case of the above form mixin. At the time of login, we see a form which asks for the user’s credentials to validate if the user is already registered or not. To create that login form we use form mixin. The code for login-form.js looks like this.

export default Component.extend(FormMixin, {
getValidationRules() {
fields : {
        identification: {
          identifier : 'email',
          rules      : [
              type   : 'empty',
              prompt : this.l10n.t('Please enter your email ID')
              type   : 'email',
              prompt : this.l10n.t('Please enter a valid email ID')
        password: {
          identifier : 'password',
          rules      : [
              type   : 'empty',
              prompt : this.l10n.t('Please enter your password')

The complete code can be found here.

We can see that in above code we are creating the form by extending our FormMixin which means that the form will have all the properties which are part of mixin along with the properties which remain unique to this class. Since the validation rules remain unique per form so we’re also providing the rules (easy to comprehend) which will help in validating the fields.

This is how our forms look like after and before applying validation rules.

Fig. 1: Login form before applying validation rules

          Fig. 2: Login form after applying validation rules

To sum it up, we can say that mixins are of great use when we want to keep our code DRY or reduce the code duplication. It helps in removing the unnecessary inheritance keeping it short. The code written using mixin is lesser complex and easily understandable.


Continue ReadingEmber Mixins used in Open Event Frontend

Supporting Dasherized Attributes and Query Params in flask-rest jsonapi for Open Event Server

In the Open Event API Server project attributes of the API are dasherized.

What was the need for dasherizing the attributes in the API ?

All the attributes in our database models are separated by underscores i.e first name would be stored as first_name. But most of the API client implementations support dasherized attributes by default. In order to attract third party client implementations in the future and making the API easy to set up for them was the primary reason behind this decision.Also to quote the official json-api spec recommendation for the same:

Member names SHOULD contain only the characters “a-z” (U+0061 to U+007A), “0-9” (U+0030 to U+0039), and the hyphen minus (U+002D HYPHEN-MINUS, “-“) as separator between multiple words.

Note: The dasherized version for first_name will be first-name.

flask-rest-jsonapi is the API framework used by the project. We were able to dasherize the API responses and requests by adding inflect=dasherize to each API schema, where dasherize is the following function:

def dasherize(text):
   return text.replace('_', '-')


flask-rest-jsonapi also provides powerful features like the following through query params:

But we observed that the query params were not being dasherized which rendered the above awesome features useless 🙁 . The reason for this was that flask-rest-jsonapi took the query params as-is and search for them in the API schema. As Python variable names cannot contain a dash, naming the attributes with a dash in the internal API schema was out of the question.

For adding dasherizing support to the query params, change in the QueryStringManager located at of the framework root are required. A config variable named DASHERIZE_APIwas added to turn this feature on and off.

Following are the changes required for dasherizing query params:

For Sparse Fieldsets in the fields function, replace the following line:

result[key] = [value]
if current_app.config['DASHERIZE_API'] is True:
    result[key] = [value.replace('-', '_')]
    result[key] = [value]


For sorting, in the sorting function, replace the following line:

field = sort_field.replace('-', '')


if current_app.config['DASHERIZE_API'] is True:
   field = sort_field[0].replace('-', '') + sort_field[1:].replace('-', '_')
   field = sort_field[0].replace('-', '') + sort_field[1:]


For Include related objects, in include function, replace the following line:

return include_param.split(',') if include_param else []


if include_param:
   param_results = []
   for param in include_param.split(','):
       if current_app.config['DASHERIZE_API'] is True:
           param = param.replace('-', '_')
   return param_results
return []

Related links:

Continue ReadingSupporting Dasherized Attributes and Query Params in flask-rest jsonapi for Open Event Server

Running Dredd Hooks as a Flask App in the Open Event Server

The Open Event Server is based on the micro-framework Flask from its initial phases. After implementing API documentation, we decided to implement the Dredd testing in the Open Event API.

After isolating each request in Dredd testing, the real challenge is now to bind the database engine to the Dredd Hooks. And as we have been using Flask-SQLAlchemy db.Model Baseclass for building all the models and Flask, being a micro framework itself, came to our rescue as we could easily bind the database engine to the Flask app. Conventionally dredd hooks are written in pure Python, but we will running them as a self contained Flask app itself.

How to initialise this flask app in our dredd hooks. The Flask app can be initialised in the before_all hook easily as shown below:

def before_all(transaction):
    app = Flask(__name__)


The database can be binded to the app as follows:

def before_all(transaction):
app = Flask(__name__)
Migrate(app, db)


The challenge now is how to bind the application context when applying the database fixtures. In a normal Flask application this can be done as following:

with app.app_context():
#perform your operation


While for unit tests in python:

with app.test_request_context():
#perform tests


But as all the hooks are separate from each other, Dredd-hooks-python supports idea of a single stash list where you can store all the desired variables(a list or the name stash is not necessary).

The app and db can be added to stash as shown below:

def before_all(transaction):
app = Flask(__name__)
Migrate(app, db)
stash['app'] = app
stash['db'] = db


These variables stored in the stash can be used efficiently as below:

def before_each(transaction):
with stash['app'].app_context():
db.engine.execute("drop schema if exists public cascade")
db.engine.execute("create schema public")


and many other such examples.

Related Links:
1. Testing Your API Documentation With Dredd:
2. Dredd Tutorial:
3. Dredd Docs:

Continue ReadingRunning Dredd Hooks as a Flask App in the Open Event Server

Know the Usage of all Emoji’s on Twitter with loklak Emoji Heatmap

Loklak apps page now has a new app in its store, Emoji Heatmap. This app can be used to see the usage of all the emoji’s in the tweets all over the world in the form of heatmap. So, the major difference between the emoji heatmap and emoji heatmapper apps are heatmapper shows the tweets related to specific search query whereas this heatmapper app, it displays all the tweets which contains emojis.

How do the App fetches and stores the locations

The emoji heatmap uses the loklak search API . The search API needs a query in order to search and output the JSON data. But this app takes no input from the user end to search any query. To make the search dynamic, we are using an existing JSON file from emojiHeatmapper app and loklak-fetcher-client javascript file. From the emoji.json file, we collect the each query item and search it using loklak-fetcher-client. The output json file which we get from loklak-fetcher-client is retrieved into the emojiHeatmap and we extract the location parameter. The location parameter is then stored into the “feature” option of open layers 3 maps.

So, here in the emoji Heatmap app, we iterate over the emoji.json, get different search query each time when we search for it using loklak search API.

Code which adds the location retrieved into feature

  $.getJSON("../emojiHeatmapper/emoji.json", function(json) {
    for (var i = 0; i <; i++){
      var query =[i][1];
      // Fetch loklak API data, and fill the vector
      loklakFetcher.getTweets(query, function(tweets) {
        for(var i = 0; i < tweets.statuses.length; i++) {
          if(tweets.statuses[i].location_point !== undefined){
          // Creation of the point with the tweet's coordinates
          //  Coords system swap is required: OpenLayers uses by default
          //  EPSG:3857, while loklak's output is EPSG:4326
            var point = new ol.geom.Point(ol.proj.transform(tweets.statuses[i].location_point, 'EPSG:4326', 'EPSG:3857'));
            vector.addFeature(new ol.Feature({  // Add the point to the data vector
              geometry: point,
              weight: 20


The above function gets has two variables query and point. The query variable stores the data that is being retrieved from the emoji.json file each time it iterates and that query is being sent into the loklak-fetcher-client. Then the point variable is in which the location tracked using the loklak search API is converted into the co-ordinates system followed by the Open Layers 3. Then the point is added as a feature to the map vector. The map vector is the place where all the features are stored and then appended onto the map as a heatmap.


Continue ReadingKnow the Usage of all Emoji’s on Twitter with loklak Emoji Heatmap

Utilizing Readiness Probes for loklak Dependencies in Kubernetes

When we use any application and fail to connect to it, we do not give up and retry connecting to it again and again. But in the reality we often face this kind of obstacles like application that break instantly or when connecting to an API or database that is not ready yet, the app gets upset and refuses to continue to work. So, something similar to this was happening with
In such cases we can’t really re-write the whole application again every time the problem occurs.So for this we need to define dependencies of some kind that can handle the situation rather than disappointing the users of loklak app.


We will just wait until a dependent API or backend of loklak is ready and then only start the loklak app. For this to be done, we used Kubernetes Health Checks.

Kubernetes health checks are divided into liveness and readiness probes.
The purpose of liveness probes are to indicate that your application is running.
Readiness probes are meant to check if your application is ready to serve traffic.
The right combination of liveness and readiness probes used with Kubernetes deployments can:
Enable zero downtime deploys
Prevent deployment of broken images
Ensure that failed containers are automatically restarted

Pod Ready to be Used?

A Pod with defined readiness probe won’t receive any traffic until a defined request can be successfully fulfilled. This health checks are defined through the Kubernetes, so we don’t need any changes to be made in our services (APIs). We just need to setup a readiness probe for the APIs that loklak server is depending on. Here you can see the relevant part of the container spec you need to add (in this example we want to know when loklak is ready):

            path: /api/status.json
            port: 80
          initialDelaySeconds: 30
          timeoutSeconds: 3


Readiness Probes

Updating deployments of loklak when something pushed into development without readiness probes can result in downtime as old pods are replaced by new pods in case of Kubernetes deployment. If the new pods are misconfigured or somehow broken, that downtime extends until you detect the problem and rollback.
With readiness probes, Kubernetes will not send traffic to a pod until the readiness probe is successful. When updating a loklak deployment, it will also leave old one’s running until probes have been successful on new copy. That means that if loklak server new pods are broken in some way, they’ll never see traffic, instead old pods of loklak server will continue to serve all traffic for the deployment.


Readiness probes is a simple solution to ensure that Pods with dependencies do not get started before their dependencies are ready (in this case for loklak server). This also works with more than one dependency.


Continue ReadingUtilizing Readiness Probes for loklak Dependencies in Kubernetes

How Settings of SUSI Android App Are Saved on Server

The SUSI Android allows users to specify whether they want to use the action button of soft keyboard as carriage return or else send action. The user can use SUSI.AI on different client like Android , iOS, Web. To give user uniform experience, we need to save user settings on the server so that if the user makes any change in setting in any chat client then that it changes in other chat clients too. So every chat client must store user specific data on the server to make sure that all chat clients access this data and maintain the same state for that particular user and must accordingly push and pull user data from and to the server to update the state of the app.

We used special key to store setting information on server. For eg.

Setting Key Value Use
Enter As Send enter_send true/false true means pressing enter key send message and false means pressing enter key adds new line.
Mic Input mic_input true/false true means default input method is speech but supports keyboard input too. false means the only input method is keyboard input.
Speech Always speech_always true/false true means we get speech output irrespective of input type.
Speech Output speech_output true/false true means we get speech output in case of speech input and false means we don’t get speech output.
Theme theme dark/light dark means theme is dark and light means theme is light

How setting is stored to server

Whenever user settings are changed, the client updates the changed settings on the server so that the state is maintained across all chat clients. When user change setting, we send three parameters to the server ‘key’, ‘value’ and ‘token’. For eg. let ‘Enter As Send’ is set to false. When user changes it from false to true, we immediately update it on the server. Here key will be ‘enter_send’ and value will be ‘true’.

The endpoint used to add or update User Settings is :


SETTING_NAME’ is the key of the corresponding setting, ‘SETTING_VALUE’ is it’s updated value and ‘ACCESS_TOKEN’ is used to find correct user account. We used the retrofit library for network call.

settingResponseCall = ClientBuilder().susiApi .changeSettingResponse(key, value,  PrefManager.getToken())

If the user successfully updated the setting on the server then server reply with message ‘You successfully changed settings of your account!’

How setting is retrieved from server

We retrieve setting from the server when user login. The endpoint used to fetch User Settings is


It requires “ACCESS_TOKEN” to retrieve setting data for a particular user. When user login, we use getUserSetting method to retrieve setting data from the server. PrefManager.getToken() is used to get “ACCESS_TOKEN”.

userSettingResponseCall = ClientBuilder().susiApi .getUserSetting(PrefManager.getToken())

We use userSettingResponseCall to get a response of ‘UserSetting’ type using which we can retrieve different setting from the server. ‘UserSetting’ contain ‘Session’ and ‘Settings’ and ‘Settings’ contain the value of all settings. We save the value of all settings on the server in string format, so after retrieving settings we convert them into the required format. For eg. ‘Enter As Send’ value is of boolean format, so after retrieving we convert it to boolean format.

var settings: Settings ?= response.body().settings



Continue ReadingHow Settings of SUSI Android App Are Saved on Server

How to Show Preview of Any Link in SUSI Android App

Sometimes in a chat app like Whatsapp, messenger we find that scrolling over a link, shows a preview of the link. Android-Link-Preview is an open source library which can be used to show the preview of a link. This library is developed by Leonardo Cardoso. This library makes preview from an url using all the information such as title, relevant texts and images. TextCrawler is the main class of this library. As the name suggests this class is used to crawl given link and grab relevant information. In this blog, I will show you how I used this library in SUSI Android to show the preview of the link.

How to include this library in your project

To use android-link-preview in our project we must add the dependency of the library in build.gradle(project) file

repositories {
  maven { url’   }

and build.gradle(module) file.

dependencies {
   compile org.jsoup:jsoup:1.8.3 // required
   compile com.leocardz:link-preview:1.2.1@aar

Now import these packages in class where you want to use link preview.




As the name suggests LinkpreviewCallback is a callback which has two important methods onPre() and onPos(). onPre() method called when library starts crawling the web to find relevant information and onPos() method called when crawling finished. This library uses SourceContent class to save and retrieve data.

LinkPreviewCallback linkPreviewCallback = new LinkPreviewCallback() {


public void onPre() { }


public void onPos(final SourceContent sourceContent, boolean b) {}


TextCrawler class is the main class which use makePreview() method to start web crawling.

makePreview() method needs two parameters

  • linkPreviewCallback : Instance of LinkPreviewCallback class.
  • Link : Link of web page to crawl.
TextCrawler textCrawler = new TextCrawler();

textCrawler.makePreview(linkPreviewCallback, link);

So when we call makePreview method, this library starts crawling the web. But before that, it checks if given link is URL of any image or not. If given link is URL of any image, then there is no need of crawling the web because we can’t find any other information from that link, but if it is not url of any image then it starts crawling the web. All websites are written in HTML. It uses jsoup library to parse HTML documents and extract useful data from that web page. After that it store different information separately i.e it store ‘title’, ‘description’ and ‘image url’ separately using setTitle(), setDescription() and setImage() methods of SourceContent class respectively.


When it finishes all these tasks, it call onPos() method of LinkPreview class to inform that it has done its task and now we can use stored data using getTitle(), getDescription() and getImage() methods inside onPos() method.


Example :

We are using Android-link-preview in our SUSI Android app


Continue ReadingHow to Show Preview of Any Link in SUSI Android App

Implementing a Collapsible Responsive App Bar of SUSI Web Chat

In the SUSI Web Chat application we wanted to make few static pages such as: Overview, Terms, Support, Docs, Blog, Team, Settings and About. The idea was to show them in app bar. Requirements were  to have the capability to collapse on small viewports and to use Material UI components. In this blog post I’m going to elaborate how we built the responsive app bar Using Material UI components.

First we added usual Material UI app bar component  like this.

             <header className="nav-down" id="headerSection">
title={<a href={this.state.baseUrl} ><img src="susi-white.svg" alt="susi-logo"  className="siteTitle"/></a>}
               iconElementRight={<TopMenu />}

We added SUSI logo instead of the text title using below code snippet and linked it to the home page like this.

title={<a href={this.state.baseUrl} ><img src="susi-white.svg" alt="susi-logo"  className="siteTitle"/></a>}

We have defined “this.state.baseUrl” in constructor and it gets the base url of the web application.

this.state = {
       openDrawer: false, 
baseUrl: window.location.protocol + '//' + + '/'

We need to open the right drawer when we click on the button on top left corner. So we have to define two methods to open and close drawer as below.

   handleDrawer = () => this.setState({openDrawer: !this.state.openDrawer});
   handleDrawerClose = () => this.setState({openDrawer: false});

Now we have to add components that we need to show on the right side of the app bar. We connect those elements to the app bar like this. “iconElementRight={}”

We defined “TopMenu” Items like this.

   const TopMenu = (props) => (
     <div className="top-menu">
     <FlatButton label="Overview"  href="/overview" style={{color:'#fff'}} className="topMenu-item"/>
     <FlatButton label="Team"  href="/team" style={{color:'#fff'}} className="topMenu-item"/>

We added FlatButtons to place links to other static pages. After all we needed a FlatButton that gives IconMenu to show login and signup options.

     <IconMenu {...props} iconButtonElement={
         <IconButton iconStyle={{color:'#fff'}} ><MoreVertIcon /></IconButton>
     <MenuItem primaryText="Chat" containerElement={<Link to="/logout" />}

After adding all these correctly you will see this kind of an app bar in your application.

Now our app bar is ready. But it does not collapse on small viewports.
So we planned to hide flat buttons on small sized screens and show the menu button. For that we used media queries.

@media only screen and (max-width: 800px){
   .topMenu-item{ display: none !important;  }
   .topAppBar button{ display: block  !important; }

This is how we built the responsive app bar using Material UI components. You can check the preview from this url. If you are willing to contribute to SUSI Web Chat here is the GitHub repository.


  • Material UI Components:
  • Learn More about media queries:
Continue ReadingImplementing a Collapsible Responsive App Bar of SUSI Web Chat