<body>
  <div id="wrapper">
    <div id="sidebar-wrapper">
      <ul class="sidebar-nav">
        <li>
          <a class="nohover" href="index.html"><img class="twitch-img img-responsive" src="https://dl.dropboxusercontent.com/s/9d32agss7hkk34h/twitch-logo3.png" alt="twitch logo"></a>
        </li>
        <li id="search">
          <input class="searching form-control" type="text" placeholder="Search...">
        </li>
        <li>
          <a id="all" href="#">All</a>
        </li>
        <li>
          <a id="online"  href="#">Online</a>
        </li>
        <li>
          <a id="offline" href="#">Offline</a>
        </li>
      </ul>
    </div>

    <div id="page-content-wrapper">
      <div class="container-fluid">
        <div class="heading row">
          <div class="col-xs-12">
            <a href="#" class="btn btn-default" id="menu-toggle">Menu</a>
            <h1 class="title text-center">Twitch TV Status</h1>    
          </div>
        </div>
        
        <div class="row">
              <div id="loader" class="col-xs-12 text-center">
                <p class="loading">Loading.....</p>
            </div>
        </div>

        <div class="main-content row">    
           
        </div>
        
      </div>
    </div>
  </div>
</body>
@import url(https://fonts.googleapis.com/css?family=Roboto:400,700);
@import url(https://fonts.googleapis.com/css?family=Nunito:400,700);

/* THE SIDEBAR EFFECT CREDIT T0 : https://startbootstrap.com */
/*

 * Start Bootstrap - Simple Sidebar HTML Template (https://startbootstrap.com)
 * Code licensed under the Apache License v2.0.
 * For details, see http://www.apache.org/licenses/LICENSE-2.0.
 */
h1,h2,h3,h4,h5,h6{
  font-family: 'Roboto', sans-serif;
}

a{
  color:#615192;
}

a:hover,
a:active,
a:focus,
a:visited{
  text-decoration:none;
}

body{
  background:#764B8E;
  font-family: 'Nunito', sans-serif;
}

.twitch-img{  
  width:300px;
}

#search{
  padding:10px 18px;
}

#menu-toggle{
  margin-top:-15px;
  margin-left:-30px;
 
}

.title{
  font-family: 'Roboto', sans-serif;
  font-size:60px;
  font-weight:bold;
  color:#f5f5f5;
  margin-top:50px;
  margin-bottom:100px;
}



.status-text{
  display:inline-block;
  margin:6px 0 0 0;
}



.panel{
  max-width:300px;
  height:430px;
}

.panel-default{
  border: 0;
}

.panel .panel-info {
    padding: 0;
}

.loading{
  font-size:40px;
}
#wrapper {
    padding-left: 0;
    -webkit-transition: all 0.5s ease;
    -moz-transition: all 0.5s ease;
    -o-transition: all 0.5s ease;
    transition: all 0.5s ease;
}

#wrapper.toggled {
    padding-left: 250px;
}

#sidebar-wrapper {
    z-index: 1000;
    position: fixed;
    left: 250px;
    width: 0;
    height: 100%;
    margin-left: -250px;
    overflow-y: auto;
    background:#261758;
    -webkit-transition: all 0.5s ease;
    -moz-transition: all 0.5s ease;
    -o-transition: all 0.5s ease;
    transition: all 0.5s ease;
}

#wrapper.toggled #sidebar-wrapper {
    width: 250px;
}

#page-content-wrapper {
    width: 100%;
    position: absolute;
    padding: 15px;
    
}

#wrapper.toggled #page-content-wrapper {
    position: absolute;
    margin-right: -250px;
}

/* Sidebar Styles */

.sidebar-nav {
    position: absolute;
    top: 0;
    width: 250px;
    margin: 0;
    padding: 0;
    list-style: none;
   
}

.sidebar-nav li {
    text-indent: 20px;
    line-height: 40px;

}

.sidebar-nav li a {
    display: block;
    text-decoration: none;
    color: #f5f5f5;
}

.sidebar-nav li a:not(.nohover):hover {
    text-decoration: none;
    color: #fff;
    background: rgba(255,255,255,0.2);
}

.sidebar-nav li a:active,
.sidebar-nav li a:focus {
    text-decoration: none;
}

@media(min-width:620px) {
  .title{
  
  font-size:72px;
}
  
    #wrapper {
        padding-left: 250px;
    }

    #wrapper.toggled {
        padding-left: 0;
    }

    #sidebar-wrapper {
        width: 250px;
    }

    #wrapper.toggled #sidebar-wrapper {
        width:0px;
    }

    #page-content-wrapper {
        padding: 20px;
        position: relative;
      
    }

    #wrapper.toggled #page-content-wrapper {
        position: relative;
        margin-right: 0;
    }
}
(function($){
  "use strict"
  var twitchBaseUrl = 'https://api.twitch.tv/kraken/streams/'
  var twitchUserNames = ["freecodecamp", "storbeck", "terakilobyte", "habathcx", "RobotCaleb", "thomasballinger", "noobs2ninjas", "beohoff", "medrybw", "brunofin", "comster404"];
  var defaultlogo = "https://dl.dropboxusercontent.com/s/c189pkhw98kxq5l/default-logo.jpg"; //  default logo if user dont have one
  var closedlogo = "https://dl.dropboxusercontent.com/s/vpc3wuq4vr2prb1/closedAccount.png"; // closed account logo
  var greenStatus = "https://dl.dropboxusercontent.com/s/zmjmj8u7kw4vryq/green-statv2.png";
  var redStatus = "https://dl.dropboxusercontent.com/s/2amcjasm2kydzj6/red-statusv2.png";

  var twitchUserInfo = [];  // all users data to be stored in
  var onlineUsers = [];  // online user data to be stored in
  var offlineUsers = [];  //offline user data to be stored in

  var totalRequest = (twitchUserNames.length * 2); // total request thats going to be made 
  var completedRequest = 0; // keep track of requests
  var closedAccount = 0; // counting closed account thats not going to make a second request
  
  
  
  //get twitch user stream data first
  function getTwitchStreamData(){
    twitchUserNames.forEach(function(names, index) {
      $.ajax({url:twitchBaseUrl + names + '?client_id=l2y4sabamn5zz4gk8p2h1r0x3binu51&callback=?',dataType:'jsonp',error:function(xhr,status,error){
          // handle closed account when 'GET' request completely fails 
          twitchClosedAccount(names,index);
       }}).then(function(theStream) {
        if(theStream._links){
         twitchUserInfo[index] = {};
         twitchUserInfo[index].user_stream = (theStream.stream ? true : false);
        if (twitchUserInfo[index].user_stream) {
          onlineUsers.push(twitchUserInfo[index]);
        } else {
          offlineUsers.push(twitchUserInfo[index]);
        }
          completedRequest += 1;
          // get user channel data next
          getTwitchChannelData(theStream._links.channel,index);
        }else{
          // handle special case when twitch api handle a 'GET' request on a closed account and returns an error object 
          twitchClosedAccount(names,index);
        }
      });
    });               
  }


  // later get channel data after getting stream data
  function getTwitchChannelData(url,index){
    $.ajax({url:url + '?client_id=l2y4sabamn5zz4gk8p2h1r0x3binu51&callback=?',dataType:'jsonp'}).then(function(theChannel){
        console.log(theChannel)
        twitchUserInfo[index].user_name = theChannel.display_name;
        twitchUserInfo[index].user_logo = (theChannel.logo ? theChannel.logo : defaultlogo);
        twitchUserInfo[index].user_url = theChannel.url;
        twitchUserInfo[index].user_status = (twitchUserInfo[index].user_stream ? "Online" : "Offline");
        twitchUserInfo[index].user_status_details = (twitchUserInfo[index].user_stream ? theChannel.status : null);
        // trim string at length greater than 22
        if (twitchUserInfo[index].user_status_details) {
          twitchUserInfo[index].user_status_details = (twitchUserInfo[index].user_status_details.length > 22 ? twitchUserInfo[index].user_status_details.substring(0, 22) + "..." : twitchUserInfo[index].user_status_details)
        }
        twitchUserInfo[index].icon_status = (twitchUserInfo[index].user_stream ? greenStatus : redStatus);
        completedRequest += 1;
    })
  }

  function twitchClosedAccount(names,index){
          closedAccount += 1; 
          twitchUserInfo[index] = {};
          offlineUsers.push(twitchUserInfo[index]);
          // default values for closed accounts
          twitchUserInfo[index].user_name = names;
          twitchUserInfo[index].user_logo = closedlogo;
          twitchUserInfo[index].user_url = '#'
          twitchUserInfo[index].user_status = "Offline";
          twitchUserInfo[index].user_status_details = "Account Closed"
          twitchUserInfo[index].icon_status = redStatus;
          completedRequest += 1;
  }



  function getAll(){
    $('#all').on('click',function(e){
      e.preventDefault();
      $('.main-content').empty();
     twitchUserInfo.forEach(function(twitchUser) {
      var baseContent = "<div class='col-xs-12 col-sm-6 col-md-4'>" +
        "<div class='panel panel-default'>" +
        "<div class='panel-info'>" +
        "<img src='" + twitchUser.user_logo + "' class='img-responsive'>" +
        "</div>" +
        "<div class='panel-body'>" +
        "<p class='lead'>" +
        "<a href='" + twitchUser.user_url + "'" + " target='_blank'>" + twitchUser.user_name + "</a></p>" +
        "<p class='status-text'>Status: " + twitchUser.user_status + "</p>" +
        "<img class='status-img pull-right'" + "src='" + twitchUser.icon_status + "'/>";

      if (twitchUser.user_status_details) {
        baseContent = baseContent + "<p>" + twitchUser.user_status_details + "</p>" + "</div>" + "</div>" + "</div>";
        $('.main-content').append(baseContent);
      } else {
        baseContent = baseContent + "</div>" + "</div>" + "</div>";
        $('.main-content').append(baseContent);
      }
    }); 
    }) 
  }

  function getOnline(){
    $('#online').on('click', function(e) {
      e.preventDefault();
      $('.main-content').empty();
      onlineUsers.forEach(function(onlineUser) {
        var Content = "<div class='col-xs-12 col-sm-6 col-md-4'>" +
          "<div class='panel panel-default'>" +
          "<div class='panel-info'>" +
          "<img src='" + onlineUser.user_logo + "' class='img-responsive'>" +
          "</div>" +
          "<div class='panel-body'>" +
          "<p class='lead'>" +
          "<a href='" + onlineUser.user_url + "'" + " target='_blank'>" + onlineUser.user_name + "</a></p>" +
          "<p class='status-text'>Status: " + onlineUser.user_status + "</p>" +
          "<img class='status-img pull-right'" + "src='" + onlineUser.icon_status + "'/>" +
          "<p>" + onlineUser.user_status_details + "</p>" +
          "</div>" +
          "</div>" +
          "</div>"
        $('.main-content').append(Content);
      })
    })  
  }

  function getOffline(){
     $('#offline').on('click',function(e){
      e.preventDefault();
      $('.main-content').empty();
          offlineUsers.forEach(function(offlineUser){
            var baseContent = "<div class='col-xs-12 col-sm-6 col-md-4'>" +
            "<div class='panel panel-default'>" +
            "<div class='panel-info'>" +
            "<img src='" + offlineUser.user_logo + "' class='img-responsive'>" +
            "</div>" +
            "<div class='panel-body'>" +
            "<p class='lead'>" +
            "<a href='" + offlineUser.user_url + "'" + " target='_blank'>" + offlineUser.user_name + "</a></p>" +
            "<p class='status-text'>Status: " + offlineUser.user_status + "</p>" +
            "<img class='status-img pull-right'" + "src='" + offlineUser.icon_status + "'/>";

          if (offlineUser.user_status_details) {
            baseContent = baseContent + "<p>" + offlineUser.user_status_details + "</p>" + "</div>" + "</div>" + "</div>";
            $('.main-content').append(baseContent);
          } else {
            baseContent = baseContent + "</div>" + "</div>" + "</div>";
            $('.main-content').append(baseContent);
          }    
      })   
    })  
  }

  // runs when all async request have been completed
  function DisplayTwitchUserData(stopInterval) {
    clearInterval(stopInterval);
    // load all on intial start up
    twitchUserInfo.forEach(function(twitchUser) {
      var baseContent = "<div class='col-xs-12 col-sm-6 col-md-4'>" +
        "<div class='panel panel-default'>" +
        "<div class='panel-info'>" +
        "<img src='" + twitchUser.user_logo + "' class='img-responsive'>" +
        "</div>" +
        "<div class='panel-body'>" +
        "<p class='lead'>" +
        "<a href='" + twitchUser.user_url + "'" + " target='_blank'>" + twitchUser.user_name + "</a></p>" +
        "<p class='status-text'>Status: " + twitchUser.user_status + "</p>" +
        "<img class='status-img pull-right'" + "src='" + twitchUser.icon_status + "'/>";

      if (twitchUser.user_status_details) {
        baseContent = baseContent + "<p>" + twitchUser.user_status_details + "</p>" + "</div>" + "</div>" + "</div>";
        $("#loader").css("display", "none");
        $('.main-content').append(baseContent);
      } else {
        baseContent = baseContent + "</div>" + "</div>" + "</div>";
        $("#loader").css("display", "none");
        $('.main-content').append(baseContent);
      }
    });

    // set all, online, and offline button to be used
    getAll();
    getOnline();
    getOffline();

    // set search feature
    $('.searching').on("keyup",function(){
        var searchWord = $(this).val().toLowerCase();
        $('.panel-body .lead a').each(function(){
          var checkUserName = $(this).text().toLowerCase();
          $(this).closest('.panel')[ checkUserName.indexOf(searchWord) !== -1 ? 'show' : 'hide' ]();
        })
    })

  }

  $(document).ready(function() {
    // sidebar toggle
    $("#menu-toggle").click(function(e) {
      e.preventDefault();
      $("#wrapper").toggleClass("toggled");
    });

    // makes aysnc request to twitch server and get user twitch data 
     getTwitchStreamData();

    // check to make sure all async request have been completed 
   var completeAsyncRequest = setInterval(function() {
      if ((completedRequest !== 0) && completedRequest === (totalRequest = totalRequest - closedAccount)) {
        var stopInterval = completeAsyncRequest;
        DisplayTwitchUserData(stopInterval);
      }
    }, 2000)   
  })
})(jQuery)
Run Pen

External CSS

  1. //maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js