How to organise a successful Google Code-In meetup

In this blog post I hope to write about what is Google Code-In and the best way to organise a successful Google Code-In meetup or workshop in your local community. I hope you will find everything that you need to know about conducting a successful meetup.

What is Google Code-In ?

Google Code-In is a global and an open source contest funded by Google to give real world software development experience to pre-university students who are in age range 13-17. Beside of software developing, this contest’s main objective is to motivate tech enthusiastic students to contribute to opensource and give them the knowledge about open source software development.

The usual timeline of the contest is, it opens for students on end of the November and runs until mid of January. There are 25 open source organizations participating for Google Code-In this time.

Your role ?

As a GCI mentor , past GCI student or an open source contributor you have a responsibility towards the community. That is to expand the community awareness and transfer your knowledge to next generation. You gather experience while working on the open source projects and GCI is the best place to give your knowledge to youngsters while working with them. You should be devoted to guide students and give them an introduction to open source software development.

How students can be a part of the contest ?

Any pre-university student in age group 13-17 can register for the contest. The following four steps needs to be followed by the student to be eligible to compete in the contest.

  1. Sign up at g.co/gci after reading the Contest Rules.
  2. Ask their parent or legal guardian to sign the Parental Consent form.
  3. Find a task that interests them.
  4. Claim the task and start working while getting guidance from the mentors.

In return to their hard work and open source contribution, students can win digital certificates, t-shirts, hoodies based on their performance as well as a trip to Google HeadQuarters for Grand Prize Winner.

How to organize a local meetup ?

Since the Google Code-In contest is for pre-university students, I highly recommend that you organize a meetup for schools in the community. You can easily contact the club or society of the school which is related to Information and Communication Technology and convey your idea of the meetup so that the responsible person can get the management approval from their side to facilitate your meetup inside the school.

If you are not confident enough to conduct a session on your own maybe because this is a new experience to you, Don’t worry ! You can always call some other past GCI students, GCI mentors or open source contributors to collaborate with you in conducting a successful session. As open source world teaches us, it’s always collaboration that brings success to any project.

Taking the start to the meetup, you need to give an introduction to the Google Code-In. You may find different questions from the audience about “What is GCI?”. It is better if you can emphasize the importance of contributing to the open source projects since the students have no experience in that field. I suggest you to give students an insight on the evolvement of Google Code-In throughout the past years, so they get to know the real world statistics.

During the meetup, you need to focus on the 05 types of tasks that are available for students to claim, giving insights to what are the small small things that they really need to use in each task type.

  1. Coding
    • Give insights into GitHub and how to make a GitHub account, how to clone a project repository to their local machines and how to make a pull request.
  2. Documents and Training
    • Give insights into standard ways of doing documentation and basics to follow when conducting a user training.
  3. Outreach and Research
    • Give insights into how to make a blog account and write a blog as well as how to do some research on the project areas.
  4. Quality Assurance
    • Give insights into the measures that we take to assure the quality of the project and the steps that we take in order to make sure the project is adhered to the relevant quality measures.
  5. User Interface
    • Give insights into basic wireframing software like Balsamic as well as guidelines to a successful user experience.

It is really appreciated if you can share your experiences in open source contributions with them like what did you do, what you will be doing next and what obstacles that you had to face while contributing and how did you overcome those challenges. This will be an eye opener for them to think beyond the comfort zone. This section will be really helpful for the students to grab really what open source contributing is.

It is a best practice to conduct the session in an interactive way getting things done out of the box so that the students won’t get bored and they feel more energetic and comfortable since they feel that their opinion is also valued when we give time for their voice as well. Always motivate them to ask questions in the moments that they need more clarifications about what you are saying. In return if you have swags from Google, give them too since they will love it.

Always try to localize the session according to the audience that you are talking to. Use the language the majority of the audience is feasible with in order to make the meetup content more understandable to the community. You can use some slides so that you won’t miss the sections that you are going to talk about and the presentation flow will be really smooth to the initiative. Try to take an offline slide set with you in a USB drive, if you are making your presentation on Google Slides. Same for any videos that you are going to show up too.

Don’t forget to bring necessary cables/ converters(projector converters) with you and always remember to have a good internet connection with you if you are using internet for demos or other things  to eliminate connectivity issues which interrupt the meetup at some points and it is not a good impression to the students.

So far I wrote about how to organize a successful meetup in your local community on Google Code-In and hope this information will be very useful for you which I gathered through my own experiences when conducting the local meetups. I’m waiting to see some new meetups coming soon from all of you guys. Good Luck !

 

References

Automatically deploy SUSI Web Chat on surge after Travis passes

We are using surge from the very beginning of this SUSI web chat and SUSI skill cms projects development. We used surge for provide preview links for Pull requests. Surge is really easy tool to use. We can deploy our static web pages really easily and quickly.  But If user had to change something in pull request user has to deploy again in surge and update the link. If we can connect this operation with travis ci we can minimise re-works. We can embed the deploying commands inside the travis.yml.

We can tell travis to make a preview link (surge deployment) if test cases are passed by embedding the surge deployment commands inside the travis.yml like below.

This is travis.yml file

sudo: required
dist: trusty
language: node_js
node_js:
 - 6
script:
 - npm test
after_success:
 - bash ./surge_deploy.sh
 - bash ./deploy.sh
cache:
 directories:
   - node_modules
branches:
 only:
   - master

Surge deployment commands are inside the “surge_deploy.sh” file.
In that we have to check the status of the pull request whether it is passing test cases or not. We can do it like below.

if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
   echo "Not a PR. Skipping surge deployment"
   exit 0
fi

Then we have to install surge in the environment. Then after install all npm packages and run build.

npm i -g surge
npm install
npm run build

Since there is a issue with displaying moving to child routes we have to take a copy of index.html file and name it as a 404.html.

cp ./build/index.html ./build/404.html

Then make two environment variables for your surge email address and surge token

export [email protected]
# surge Token (run ‘surge token’ to get token)
export SURGE_TOKEN=d1c28a7a75967cc2b4c852cca0d12206

Now we have to make the surge deployment URL (Domain). It should be unique so we made a URL that contains pull request number.

export DEPLOY_DOMAIN=https://pr-${TRAVIS_PULL_REQUEST}-susi-web-chat.surge.sh
surge --project ./build/ --domain $DEPLOY_DOMAIN;

Since all our static contents which made after the build process are in “build” folder we have to tell surge to get static html files from that.
Now make a pull request. you would find the deployment link in travis ci report after travis passed.

Expand the output of the surge_deploy.sh

You will find the deployment link as we defined in the surge_deploy.sh file

References:

  • Integrating with travis ci – https://surge.sh/help/integrating-with-travis-ci
  • React Routes to Deploy 404 page on gh-pages and surge – https://blog.fossasia.org/react-routes-to-deploy-404-page-on-gh-pages-and-surge/

Recognise new SUSI users and Welcome them

SUSI web chat application is up and running now. It gives better answers for most of the questions that users ask. But for new users application does not display a welcome message or introduction about the application. It is a distraction for new users. So a new requirement arrived that is to show a welcome message for new users or give them a introduction about the application.

To give a introduction or to show a welcome message we need to identify new users. For that I used cookies.
I added a new dialog to show welcome message and introductory video. Then placed below code in the DialogSection.js file which contains codes about every dialog-box of the application.

 <Dialog
          contentStyle={{ width: '610px' }}
          title="Welcome to SUSI Web Chat"
          open={this.props.tour}
        >
          
            width="560"
            height="315"
            src="https://www.youtube.com/embed/9T3iMoAUKYA"
            gesture="media"
            allow="encrypted-media"
            >
          
          <Close style={closingStyle} onTouchTap={this.props.onRequestCloseTour()} />
        </Dialog>

We already have installed ‘universal-cookie’ npm module in our application so we can use this module to identify cookies.
I used this way to check whether user is new or not.

           <DialogSection
             {...this.props}
             openLogin={this.state.showLogin}
              .
              .
              .
              onRequestCloseTour={()=>this.handleCloseTour}
              tour={!cookies.get('visited')}

           	/>

Now it shows dialog-box for each and every user we don’t need to display the welcome message to old users so we need to store a cookie in users computer.
I stored a cookie in users computer when user clicks on the close button of the welcome dialog-box.
Below function makes new cookie in users computer.

  handleCloseTour = ()=>{
   this.setState({
     showLogin: false,
     showSignUp: false,
     showThemeChanger: false,
     openForgotPassword: false,
     tour:false
    });
    cookies.set('visited', true, { path: '/' });
 }

 

Below line sets a cookie and { path : ’/’ } makes cookie accessible on all pages.

References:

How to Store Mobile Settings in the Server from SUSI Web Chat Settings Page

While we are adding new features and capabilities to SUSI Web Chat application, we wanted to provide settings changing capability to SUSI users. SUSI team decided to maintain a settings page to give that capability to users.

This is how it’s interface looks like now.

In this blog post I’m going to add another setting category to our setting page. This one is for  saving mobile phone number and dial code in the server.

UI Development:

First we need to  add new category to settings page and it should be invisible when user is not logged in. Anonymous users should not get mobile phone category in settings page.

     let menuItems = cookies.get('loggedIn') ?
            <div>
                <div className="settings-list">
                    <Menu
                        onItemTouchTap={this.loadSettings}
                        selectedMenuItemStyle={blueThemeColor}
                        style={{ width: '100%' }}
                        value={this.state.selectedSetting}
                    >
                       <MenuItem value='Mobile' className="setting-item" leftIcon={<MobileIcon />}>Mobile<ChevronRight className="right-chevron" /></MenuItem>
                        <hr className="break-line" />
                    </Menu>
                </div>
            </div>

 

Next we have to show settings UI when user clicks on the category name.

 if (this.state.selectedSetting === 'Mobile' && cookies.get('loggedIn')) {}
                currentSetting = (
  <Translate text="Country/region : " />
                            <DropDownMenu maxHeight={300}
               value={this.state.countryCode?this.state.countryCode:'US'}

 

Show US if the state does not deines the country code

                                onChange={this.handleCountryChange}>
                                {countries}
                            </DropDownMenu>
<Translate text="Phone number : " />
                            <TextField name="selectedCountry"
                            disabled={true}
                            value={countryData.countries[this.state.countryCode?this.state.countryCode:'US'].countryCallingCodes[0] }
                         	/>
                            <TextField name="serverUrl"
                                onChange={this.handleTelephoneNoChange}
                                value={this.state.phoneNo }
 />
)}

 

Then we need to get list of country names and country dial codes to show in the above drop down. We used country-data node module for that.

To install country-data module use this  command.

npm install --save country-data

 

We have used it in the settings page as below.

import countryData from 'country-data';
    	countryData.countries.all.sort(function(a, b) {
            if(a.name < b.name){ return -1};
            if(a.name > b.name){ return 1};
            return 0;
        });
        let countries = countryData.countries.all.map((country, i) => {
         	return (<MenuItem value={countryData.countries.all[i].alpha2} key={i} primaryText={ countryData.countries.all[i].name+' '+ countryData.countries.all[i].countryCallingCodes[0] } />);
        });

 

First we sort the country data list from it’s name. After that we made a list of “”s from this list of data.
Then we have to check whether the user changed or added the phone number and region (dial code).
It handles by this function mentioned above. ( onChange={this.handleCountryChange}> and
onChange={this.handleTelephoneNoChange} )

    handleCountryChange = (event, index, value) => {
        this.setState({'countryCode': value });
    }

 

Then we have to get the phone number using below function.

    handleTelephoneNoChange = (event, value) => {
        this.setState({'phoneNo': value});
    }

 

Next we have to update the function that triggers when user clicks the save button.

    handleSubmit = () => {
        let newCountryCode = !this.state.countryCode?
        this.intialSettings.countryCode:this.state.countryCode;
        let newCountryDialCode = !this.state.countryDialCode?
        this.intialSettings.countryDialCode:this.state.countryDialCode;
        let newPhoneNo = this.state.phoneNo;
        let vals = {
            countryCode: newCountryCode,
            countryDialCode: newCountryDialCode,
            phoneNo: newPhoneNo
}
let settings = Object.assign({}, vals);
cookies.set('settings', settings);
 this.implementSettings(vals);
 }

 

This code snippet stores Country Code, Country Dial code and phone no in the server.
Now we have to update the Store. Here we are going to change UserPreferencesStore “UserPreferencesStore” .
First we have to setup default values for things we are going to store.

let _defaults = {
	  CountryCode: 'US',
   	  CountryDialCode: '+1',
   	  PhoneNo: ''
}

 

Finally we have to update the dispatchToken to change and get these new data

UserPreferencesStore.dispatchToken = ChatAppDispatcher.register(action => {
   switch (action.type) {
       case ActionTypes.SETTINGS_CHANGED: {
           let settings = action.settings;
           if(settings.hasOwnProperty('theme')){
                   _defaults.Theme = settings.theme;
           }
           if(settings.hasOwnProperty('countryDialCode')){
               _defaults.countryDialCode = settings.countryDialCode;
           }
           if(settings.hasOwnProperty('phoneNo')){
               _defaults.phoneNo = settings.phoneNo;
           }
           if(settings.hasOwnProperty('countryCode')){
               _defaults.countryCode = settings.countryCode;
           }
           UserPreferencesStore.emitChange();
           break;
}
}

 

Finally application is ready to store and update Mobile phone number and region code in the server.

Resources:

Implementation of Child Routes in SUSI Skill CMS

In a previous blog post I discussed about how we implemented routing in SUSI Web Chat Application. In this post I’m planning to discuss about how we developed child routes in SUSI Skill CMS .

When we start developing our application, it was working correctly but  all skills loaded in the same URL. ( skill.susi.ai/SkillPage ). When user clicks the edit button every skill loaded in the same URL ( skill.susi.ai/EditSkill ). We got a requirement to load each of our skills in separate routes. This is how we implemented the child routes of the application.

We wanted to show each individual skill under this type of URL,

skill.susi.ai/ [SKILL GROUP] / [SKILL NAME] / [LANGUAGE]

When user clicks on the edit button, we needed to show that particular skill under this URL.

skill.susi.ai/ [SKILL GROUP] / [SKILL NAME] / edit / [LANGUAGE]

First we set our routings in index.js file.

<Switch>
    <Route exact path="/:category/:skill/edit/:lang" component={Home} />
    <Route exact path="/:category/:skill/:lang" component={SkillListing}/>
    <Route exact path="/" component={BrowseSkill} />
    <Route exact path="*" component={NotFound} />
</Switch>

We have to add the “exact” attribute, if we don’t add that it will not redirect users to “404” page when user trying to access wrong routes.

Next step is sending data from one component to another component.
In SUSI Skill CMS, user can choose any skill from the home page. Then after it goes to the skill page and shows details about the selected skill. We have to modify the button as,

<Link to={{ pathname: '/'+self.state.groupValue+'/'+el+'/'+self.state.languageValue }} >
<Card>
</Card>
</Link>

Now the user clicks on the card. It changes the URL and loads the corresponding component according to the routes that we defined in “index.js” file previously.
Second thing that we need to do is to catch URL routs and render relevant data according to the URL routes.
Let’s say I clicked on “distance” skill. Then user will go to this URL “http://skills.susi.ai/Knowledge/distance/en ”
Now It loads the “SkillListing” component according to the route we defined in “ index.js ” here ””.
To derive data from URL we simply used these codes in “SkillListing.js”.

let baseUrl = 'http://api.susi.ai/cms/getSkillMetadata.json';           
let modelValue = "general";
           this.name = this.props.location.pathname.split('/')[2];
           this.groupValue = this.props.location.pathname.split('/')[1];
           this.languageValue = this.props.location.pathname.split('/')[3];
           url = baseUrl + '?model=' + modelValue + '&group=' + this.groupValue + '&language=' + this.languageValue + '&skill=' + this.name;

We collected data from the URL and made another URL, we used this URL to get details of the skill from the server. We used this urls as below.

           $.ajax({
               url: url,
               jsonpCallback: 'pc',
               dataType: 'jsonp',
               jsonp: 'callback',
               crossDomain: true,
               success: function (data) {
                   self.updateData(data.skill_metadata)
               }
           });

If the Ajax request is success, those data are passed to “updateData()” and it updates the component and shows to users like this.

We applied same mechanism to the edit button and edit page. This is how we modified skill.susi.ai ‘s Routings. If you like to contribute SUSI Skill CMS please fork our repository on github. here

Resources:

  • Previous Blogpost about routing: https://blog.fossasia.org/implementation-of-react-routers-in-susi-web-chat/
  • React Router v4 tutorial https://medium.com/@pshrmn/a-simple-react-router-v4-tutorial-7f23ff27adf

Displaying Blog Posts on SUSI AI Web Chat’s Blog Page and Share Posts

FOSSASIA is maintaining a superior blog and it contains blog posts about projects and programs run by FOSSASIA. While we were implementing SUSI Web Chat Application we got a requirement to implement a blog page. Speciality of this blog page is it is not a separate blog page, it fetches blog posts and other related data by filtering the FOSSASIA’s main blog.

In this blog post I’ll discuss how we fetched and managed those data on front-end and how we made the appearance same as the FOSSASIA main blog.

First we get blog posts as a JSON. For that we used rss2json API. we can get the RSS feed as a JSON by sending our RSS feed URL to the rss2json API. Check the rss2json API documentation here.

It produces all posts as items array. Next we store this array of responses in our application as a state.

This response contains blog post titles featured images’ details and post content and other metadata such as tags, author name and published date.

We had few requirements to fulfill. First one is to show full content of the blogpost in a new blog page.

We can take the full content from response like this,

this.state.posts.slice(this.state.startPage, this.state.startPage + 10).map((posts, i) => {
        let content = posts.content;
})

We can use “cintent” variable to show content but it contains the featured image. We have to skip that image. For that,

let htmlContent = content.replace(/<img.*?>/, '');

Now we have to render this string value as HTML. For that we have to install “test-to-html” package using below command.

npm install html-to-text --save

Now we can convert text into html like this

htmlContent = renderHTML(htmlContent);

We used this HTML content inside the “CardText” tag.

<CardText> {htmlContent}
</CardText>

At the bottom of the post we needed to show author name, tags list and categories list.
Since tags and categories come in one array, we have to separate them.
First we defined an array which contains all the categories in Fossasia blog. Then we compared that array with the categories we got like this.

       const allCategories = ['FOSSASIA','GSoC','SUSI.AI']

Compare two arrays,

          posts.categories.map((cat) => {
                let k = 0;
                for (k = 0; k < allCategories.length; k++) {
                              if (cat === allCategories[k]) {
                                  category.push(cat);
                              }
              	}
          });

we defined this “arrDiff” simple function to get the difference of two arrays.

     var tags=arrDiff(category,posts.categories)

Make the list of categories

let fCategory=category.map((cat) =>
<span key={cat} ><a className="tagname" href={'https://blog.fossasia.org/category/' + cat.replace(/\s+/g, '-').toLowerCase()} rel="noopener noreferrer">{cat}</a></span>
   );

We can use above step to make tags list.

Then after used it in the “CardActions”

<span className='categoryContainer'>
    <i className="fa fa-folder-open-o tagIcon"></i>
    {fCategory}
</span>

 

According to the final requirement we needed to add social media share buttons for Facebook and Twitter.

If we need to make a twitter share button we have to follow up this method. But we can use “react-share” npm package to make these kind of share buttons.

This is how we made Facebook and Twitter share buttons. First of all we have to install “react-share” package using below command.

npm install react-share --save

Then we have to import the installed package.

import { ShareButtons, generateShareIcon } from 'react-share';

Then after we defined Button and Icon like this.

      const {FacebookShareButton,TwitterShareButton} = ShareButtons;
      const FacebookIcon = generateShareIcon('facebook');
      const TwitterIcon = generateShareIcon('twitter');

Now we can use these components.

<TwitterShareButton url={posts.guid} title={posts.title} via='asksusi' hashtags={posts.categories.slice(0, 4)} >                                                                                <TwitterIcon size={32} round={true} />
</TwitterShareButton>
<FacebookShareButton url={posts.link}>
     <FacebookIcon size={32} round={true} />
</FacebookShareButton>

We have to send URL and title of the post with the tweet and tags as hashtags. So we have to pass them into the component as above.
Above code produces this model of tweets.

That’s how “text-to-htm”l and “react-share” works on react. If you would like to contribute to SUSI project or any other FOSSASIA project please fork our repositories on github.

Resources:

Sorting Users and Implementing Animations on SUSI Web Chat Team Page

While we were developing the chat application, we wanted to show details of Developers.  So we planned to build a team page for SUSI Web Chat Application. In this post I discuss few things we built there. Like sorting feature, animations of the page, usage of Material UI.

First we made an array of objects to store user details. In that array we grouped them in sub arrays so we can refer them in different sections separately. We stored following data in “TeamList.js” in an array.

var team = [{
 'mentors': [{
   'name': 'Mario Behling',
   'github': 'http://github.com/mariobehling',
   'avatar': 'http://fossasia.org/img/mariobehling.jpg',
   'twitter': 'https://twitter.com/mariobehling',
   'linkedin': 'https://www.linkedin.com/in/mariobehling/',
   'blog': '#'
 }]
},{ 'server': [{
    }]
}

There was a requirement to sort developers by their name so we had to build a way to sort out array data which are in main array. This is how we built that.
The function we are going to use for sorting.

   function compare(a, b) {
     if (a.name < b.name) { return -1; }
     if (a.name > b.name) { return 1; }
     return 0;
   }

This is how we have used it to sort developers.

import team from './TeamList';
team[1].server.sort(compare);

In this function we took values of object two by two and compared.
Now we have to show these sorted information on view.
Extract data that we want from array and we used material UI Cards to show these data on view.
This is how we extracted data from the array.

   team[1].server.sort(compare);
   let server = team[1].server.map((serv, i) => {
     return ( <Card className='team-card' key={i}>
         <CardMedia className="container" >
           <img src={serv.avatar} alt={serv.name} className="image" />
           <div className="overlay" >
             <div className="text"> <FourButtons member={serv} /> </div>
           </div>
         </CardMedia>
         <CardTitle title={serv.name} subtitle={serv.designation} />
       </Card>)   })

Now it shows data on the view.
“” contains an image of the member. We need to show social media links of the user on mouseover. We did that using simple CSS. I added a block comment around those particular styles. Check those styles here.

.overlay {
 position: absolute;
 bottom: 100%;
 left: 0;
 right: 0;
 background-color: #000;
 overflow: hidden;
 width: 100%;
 height:0;
 transition: .3s ease;
 opacity:0;
}
.container:hover .overlay {
 bottom: 0;
 height: 100%;
 opacity:0.7;
}

Above lines show that how we made the animation of the overlay animation.

Now we want to show social media buttons on the overlay. We made another separate component for buttons and return those like this.

render() {
       let member= this.props.member;
       return (<div>
         <CardActions>
           <IconButton href={member.github} target="_blank" >
  <CardActions>
		</div>)}

Finally we showed those data on Team page. We returned these JSX from render(){} method.

         <div className="team-header">
           <div className="support__heading">Developers</div>
         </div>
         <div className='team-container'>{server}</div>

I have mentioned few resources which I used to implement these features. If you are willing to contribute SUSI AI Web Chat application. Fork our repository on github.

Resources

Documentation of Array.sort https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

How to use Image overlay CSS effects: https://www.w3schools.com/howto/howto_css_image_overlay.asp

Implementation of React Routers in SUSI Web Chat

When we were developing the SUSI Web Chat application we wanted to implement set of static pages with the chat application. In the start we just wanted to navigate  through different static pages and move back to the web chat application. But it takes time to load a new page when user clicks on a link. Our goal was therefore to minimize the loading time by using lazy loading. For that we used react-route .It is standard library for react js.

From the docs:

“React Router keeps your UI synced with the URL. It has a simple API with powerful features like lazy code loading, dynamic route matching, and location transition handling built right in. Make the URL your first thought, not an after-thought.” (https://www.npmjs.com/package/react-router-plus)

We need react-route to be installed in our application first. We can install it using NPM by running this command on project folder.

npm install --save react-router-dom

Next we have to set up our routes. We have two types of headers in our application. One is chat application header, second one is static page header. In static page header we have a navigation to switch between static pages.
First we need to choose the router type because there are two types of routers in react. “” and “” we can use “” in our example because our server can handle dynamic requests. If we are requesting data from static page we should use “” .
We used that in “” and made another new component called “” and used it on “index.js” like this.

import { BrowserRouter as Router } from 'react-router-dom';
Import App from .App;
 ReactDOM.render(
  	<IntlProvider locale={defaultPrefLanguage}>
		<Router> <App /> </Router>
	</IntlProvider>,
  	document.getElementById('root')  );

In “App.js” we can set up routes like this.

        <Switch>
            <Route exact path='/' component={ChatApp}/>
            <Route exact path="/overview" component={Overview} />
            <Route exact path='/blog' component={Blog} />
            <Route exact path="/logout" component={Logout} />
            <Route exact path="/settings" component={Settings} />
            <Route exact path="*" component={NotFound} />
        </Switch>

We use elements to render component when they match with the corresponding path. We use “path” to add router location that we need to match width the component. We use “exact” property to render the component if location exactly matches with the “path”. If we do not use “exact” property it renders when we have child routes after the path like “/blog/1 “ .
We used “” element to group routes.
We can’t use anchor () tags to navigate pages without reloading. We have to use tags instead of that. We have to replace all the places we have used

<a href= ‘URL’>lable name </a>

with this,

<Link to=’URL’>Lable name</Link>   

After doing above changes application will perform faster and it will load all page contents soon after you click the navigation links.

If you would like to join with FOSSASIA and contribute to SUSI Web Chat Application please fork this repository on Github.

Resources

How SUSI AI Web Chat Custom Theme Settings are Stored in Server

We had a feature in SUSI Web Chat to make custom themes but those themes were not storing on the server. We needed to store those theme data on server. In this post I discuss how we implemented that feature. This is the PR that I sent to solve this issue.

Previously we had two theme options. According to the user’s choice it changes theme colors. Since we needed to store custom themes and use them without any conflicts with existing “light” and “dark” themes we made another theme option called “custom”. After user clicks on the custom theme it automatically changes to “custom” mode.

This is how we did it in “onClick” of the custom theme .

    this.setState({'theme':'custom'})
     let currSettings = UserPreferencesStore.getPreferences();
     let settingsChanged = {};
     if(currSettings.Theme !=='custom'){
       settingsChanged.Theme = 'custom';
       Actions.settingsChanged(settingsChanged);
     }

Then after we collected all the chosen color values to a variable. While we store our color values on a variable we avoid the “#” letter which is at very first of the color value. Because we can’t send that value to the server with “#” character.

this.customTheme.body=state.body.substring(1);

After selecting color values user have to press the save button to push those selected values to server. We execute below method on click of the save button.

 saveThemeSettings = () => {
    let customData='';
    Object.keys(this.customTheme).forEach((key) => {
      customData=customData+this.customTheme[key]+','
    });
    this.setState({'theme':'custom'})
    let currSettings = UserPreferencesStore.getPreferences();
    let settingsChanged = {};
    if(currSettings.Theme !=='custom'){
      settingsChanged.Theme = 'custom';
      Actions.settingsChanged(settingsChanged);
    }
    Actions.customThemeChanged(customData);
    this.handleClose();
  }

Using this method we derived those data that we added into the variable and made a single string array. Then after we executed the action that we needed to execute to store data on the server.
It is “Actions.customThemeChanged(customData);”.
This action is defined in “Settings.actions.js” file.

export function customThemeChanged(customTheme) {
  ChatAppDispatcher.dispatch({
    type: ActionTypes.CHANGE_CUSTOM_THEME,
    customTheme
  });
  Actions.pushCustomThemeToServer(customTheme);
}

We used this Action name constant “CHANGE_CUSTOM_THEME” in “ChatConstant.js” file

We defined this “pushCustomThemeToServer”  function on “API.actions.js” file. here

export function pushCustomThemeToServer(customTheme){
  
  if(cookies.get('loggedIn')===null||
    cookies.get('loggedIn')===undefined) {
    return;
  }
       url = BASE_URL+'/aaa/changeUserSettings.json?'
          +'key=custom_theme_value&value='+customTheme
          +'&access_token='+cookies.get('loggedIn');
        makeServerCall(url);
}

Here we check whether user is logged in or not. If user is logged in we get the access token from cookies and attach it to the request URL and execute the “makeServerCall” function that we defined previously.

Now our data are saved on server. Use this url to check what settings you have in your user account.
api.susi.ai/aaa/listUserSettings.json?access_token=YOUR_ACCESS_TOKEN
Now we can use stored values. First we need to update state. For that we got theme values from server like this

  var themeValue=[];
   if(UserPreferencesStore.getThemeValues()){
     themeValue=UserPreferencesStore.getThemeValues().split(',');
   }

 

Here we got data from server and put it to the array.

Then after we set it to state. While adding custom theme settings to state we set the “#” character before each colour value.  Here is the code

    header: themeValue.length>4?'#'+themeValue[0]:'#4285f4',
    pane: themeValue.length>4?'#'+themeValue[1]:'#f5f4f6',
    body: themeValue.length>4?'#'+themeValue[2]:'#fff',
    composer: themeValue.length>4?'#'+themeValue[3]:'#f5f4f6',
    textarea:  themeValue.length>4?'#'+themeValue[4]:'#fff',

 

Now we have to use these data with our JSX elements. This is how we did this.

We checked the current theme mode. If it is “custom” we used the values we got from server. Otherwise we used corresponding colors for other “light” and “dark” theme. Here is the full code.

 

var bodyColor;
    var TopBarColor;
    var composerColor;
    var messagePane;
    var textArea;
switch(this.state.currTheme){
  case 'custom':{
    bodyColor = this.state.body;
    TopBarColor = this.state.header;
    composerColor = this.state.composer;
    messagePane = this.state.pane;
    textArea = this.state.textarea;
    break;
  }

You can use these variables wherever you need to show colors. As an example this is how we passed header color to top bar.

 <TopBar  header={TopBarColor} >

This is how we stored and fetched custom theme data from store.

Resources:

  • How to store and receive data from SUSI server using HTTP requests. https://github.com/fossasia/chat.susi.ai/blob/master/docs/Accounting.md
  • How Flux Architecture works: https://facebook.github.io/flux/

Implementation of SUSI Web Chat Auto Sizing Message Composer

While we are using SUSI Web Chat Application we may have to send lengthy messages. Existing application’s Message composer supports for lengthy messages but it manages a constant value for every user input. While we were developing the application we got a requirement to build a growing message composer.

Final output of this implementation produces a message composer that grows when user completes a new line until user completes 5 lines and after 5 lines it maintains a fixed size and enables scrolling.

So we tried several packages to get this done. And finally we did this  using react-textarea-autosize  it gives all these features and it gives user to customize the elements furthermore.

First we have to install the npm package:

npm install --save react-textarea-autosize

After the installation we have to import the package on top of the “MessageComposer.react.js”

import TextareaAutosize from 'react-textarea-autosize';

Next we need to use this package like this,

         <TextareaAutosize
           className='scroll'
           id='scroll'
           minRows={1}
           maxRows={5}
           placeholder="Type a message..."
           value={this.state.text}
           onChange={this._onChange.bind(this)}
           onKeyDown={this._onKeyDown.bind(this)}
           ref={(textarea) => { this.nameInput = textarea; }}
           style={{ background: this.props.textarea}}
         />

 

This package provides “minRows” and “maxRows”  attributes and we can define minimum height of the text area and maximum height it can grow. If you need to know more about auto growing text areas and to get examples refer this.

Next we wanted to hide the scrollbar which is displaying when the textarea height is exceeding.

How we hide the scrollbars  on chrome browsers.

.scroll::-webkit-scrollbar {
 	 display: none;
}

This is how we hide the scrollbar on firefox browser.

.scroll {
 	overflow: -moz-scrollbars-none;
}

Now we have to style up the textarea because it comes with default styles. We wrapped up the textarea with the div and applied our styles to that. In my case we wrapped up my textarea with  <div className=“textBack”>

This is how we styled the textarea using the wrapper div.

.textBack{
 background: #fff;
 width: 83%;
 border-radius: 40px;
 padding: 5px 20px;
 display: block;
 position: relative;
 top: 12%;
 box-sizing: content-box;
 margin: 0px 0 10px 0;
}

Our textarea is like this.

It expands when user exceeds the width of textarea.

This is how we implemented the SUSI Web Chat’s growing message composer. If you would like to contribute please fork our repository on github  

Resources: