engagementgamelab/CivicSeed

View on GitHub
client/code/admin/admin.js

Summary

Maintainability
C
1 day
Test Coverage
'use strict'
/* global ss, $, apprise */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

    admin.admin

    - Main code for admin and monitor page

 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

var allQuestions = null
var allAnswers = null
var players = null
var $body

function setupLoaders () {
  $body.on('click', '#admin-startup button', function (event) {
    var $button = $(this)
    var dataType = $button.data().type

    if ($button.prop('disabled')) {
      return
    }

    $button.removeClass('btn-success btn-error')
    $button.find('.spinner').show()

    // Disable all buttons while one is processing
    $('#admin-startup button').prop('disabled', true)

    ss.rpc('admin.startup.loadData', dataType, function (res) {
      if (res) {
        $button.addClass('btn-success')
      } else {
        // Is this adequate for error, or should rpc return an error message?
        $button.addClass('btn-error')
      }
      $button.find('.spinner').fadeOut(function () {
        $('#admin-startup button').prop('disabled', false)
      })
    })
  })
}

function setupMonitor () {
  getQuestions()

  $body.on('click', '#players', function () {
    var instance = $(this).attr('data-instance')
    ss.rpc('admin.monitor.getPlayers', instance, function (err, res) {
      if (err) {
        var errorMessage = 'Error getting players: ' + err
        console.log(errorMessage)
        apprise(errorMessage)
      } else {
        players = res
        showPlayersInfo(instance)
      }
    })
  })

  $body.on('click', '#questions', function () {
    var instance = $(this).attr('data-instance')
    showQuestions(instance)
  })

  $body.on('click', '#chat', function () {
    var instance = $(this).attr('data-instance')
    ss.rpc('admin.monitor.getRecentChat', instance, function (err, res) {
      if (err) {
        var errorMessage = 'Error getting recent chat: ' + err
        console.log(errorMessage)
        apprise(errorMessage)
      } else {
        showChat(instance, res)
      }
    })
  })

  $body.on('click', '#addPlayer', function () {
    var instance = $(this).attr('data-instance')
    showAddPlayerForm(instance)
  })

  $body.on('click', '#startStop', function () {
    var instance = $(this).attr('data-instance')
    addStartStopButton(instance)
  })

  $body.on('click', '.viewAnswers', function () {
    var index = $(this).attr('data-index')
    showPlayerAnswers(index)
  })

  $body.on('click', '.stopGameButton', function () {
    var instance = $(this).attr('data-instance')
    toggleGame(instance, false)
  })

  $body.on('click', '.startGameButton', function () {
    var instance = $(this).attr('data-instance')
    toggleGame(instance, true)
  })

  $body.on('click', '.deletePlayer', function () {
    var id = $(this).attr('data-id')
    var word = $('.input' + id).val()
    if (word.indexOf('delete') > -1) {
      deletePlayer(id, this)
    } else {
      apprise('You must type “delete” to delete this user!')
    }
  })

  $body.on('click', '.question.answer-toggle', function () {
    var npc = $(this).attr('data-resource')
    var instance = $(this).attr('data-instance')

    showQuestionAnswers(npc, instance, this)
  })

  $body.on('click', '.add-player-button', function (event) {
    event.preventDefault()

    var email = $('#add-player-email').val().match(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/gi)
    var instanceName = $(this).attr('data-instance')

    if (email) {
      ss.rpc('admin.invitecodes.checkPlayerCount', instanceName, function (space) {
        if (space === true) {
          ss.rpc('admin.invitecodes.sendInvites', email, instanceName, space, function (okay) {
            if (okay) {
              apprise('New player(s) added successfully.')
              $('#add-player-email').val('')
            } else {
              apprise('Error adding new player.')
            }
          })
        } else {
          apprise('Cannot add player. The game is full.')
        }
      })
    } else {
      apprise('Invalid e-mail address.')
    }
    return false
  })
}

function showPlayersInfo (instance) {
  var html = '<h2>All players</h2>' +
             '<p><strong>Game name: <span class="color-darkblue">' + instance + '</span></strong></p>'

  for (var i = 0; i < players.length; i++) {
    var playingTime = players[i].game.playingTime
    var hours = Math.floor(playingTime / 3600)
    var hoursRemainder = playingTime % 3600
    var minutes = Math.floor(hoursRemainder / 60)
    var seconds = playingTime % 60
    var time = hours + 'h ' + minutes + 'm ' + seconds + 's'
    var isPlaying = players[i].activeSessionID ? true : false

    html += '<div class="player' + players[i]._id + '"><h3>' + players[i].firstName + ' ' + players[i].lastName + '</h3>'
    html += '<p>Profile unlocked: ' + players[i].profileUnlocked + '</p>'
    html += '<p>Logged in: ' + isPlaying + '</p>'
    html += '<p>Time played: ' + time + '</p>'
    html += '<p>Resources collected: ' + players[i].game.resourcesDiscovered + ' / 42  <button data-index=' + i + ' class="viewAnswers btn btn-success" type="button">View Answers</button></p>'
    html += '<p>Enter "delete" to remove user permanently: <input class="input' + players[i]._id + '"></input><button data-id=' + players[i]._id + ' class="btn btn-danger deletePlayer" type="button">Delete User</button></p></div>'
  }

  $('.output').empty().append(html)
}

function showChat (instance, chat) {
  var html = '<h2>Recent Chat History</h2>' +
             '<p><strong>Game name: <span class="color-darkblue">' + instance + '</span></strong></p>' +
             '<div class="allChat">'

  if (chat.length === 0) {
    html += '<p>No one has spoken yet.</p>'
  } else {
    for (var i = 0; i < chat.length; i++) {
      var date = chat[i].when.substring(0, 10)
      var time = chat[i].when.substring(11, 20)
      html += '<p><span class="time">[' + date + ' || ' + time + ']</span><span class="who"> ' + chat[i].who + ' </span><span class="what">' + chat[i].what + '</span></p>'
    }
  }

  html += '</div>'
  $('.output').empty().append(html)
}

function showAddPlayerForm (instance) {
  var html = '<div class="row"><div class="col-sm-12">' +
              '<h2>Add Player</h2>' +
              '<p><strong>Game name: <span class="color-darkblue">' + instance + '</span></strong></p>' +
              '<p>You can add multiple new players providing a comma-separated list of e-mail addresses. Note that you cannot add more players than allowed inside each game session.</p>' +
              '</div></div>' +
              '<form id="addPlayerForm">' +
              '<div class="row control-group"><div class="col-sm-6 controls">' +
              '<input placeholder="email address(es)" id="add-player-email"></input>' +
              '</div><div class="col-sm-6">' +
              '<button data-instance="' + instance + '"class="btn btn-success add-player-button" type="submit">Add Player(s)</button>' +
              '</div></div>' +
              '</form>'
  $('.output').empty().append(html)
}

function addStartStopButton (instance) {
  var html = '<h2>Make the game active or inactive</h2>' +
              '<p><strong>Game name: <span class="color-darkblue">' + instance + '</span></strong></p>' +
              '<p><button data-instance="' + instance + '"class="btn btn-success startGameButton" type="button">Start Game</button></p><p><button data-instance="' + instance + '"class="btn btn-warning stopGameButton" type="button">Stop Game</button></p>'
  $('.output').empty().append(html)
}

function getQuestions () {
  ss.rpc('admin.monitor.init', function (err, res) {
    if (err) {
      var errorMessage = 'Error getting questions: ' + err
      console.log(errorMessage)
      apprise(errorMessage)
    } else {
      allQuestions = res.sort(sortByLevel)
    }
  })
}

function showPlayerAnswers (index) {
  var resources = players[index].game.resources
  var numNPC = allQuestions.length
  var html = '<h2>' + players[index].firstName + ' ' + players[index].lastName + '</h2>'

  for (var i = 0; i < resources.length; i++) {
    var resource = resources[i]
    var n = 0
    var found = false
    var open = false

    while (!found) {
      var question = allQuestions[n]
      if (question.resource.id === resource.id) {
        found = true
        console.log(question)
        if (question.resource.questionType === 'open') {
          open = true
          html += '<div class="question"><p class="level' + question.level + '">Q: ' + question.resource.question + '</p></div>'
        }
      }
      n++
      if (n >= numNPC) {
        found = true
      }
    }

    // Answer only if open ended
    if (open) {
      html += '<div class="answer"><p>A: ' + resource.answers[0] + '</p><div class="extras">'
      if (resource.madePublic) {
        // Put unlocked icon
        html += '<i class="fa fa-unlock-alt fa-lg"></i>'
      }
      if (resource.seeded) {
        // Thumbs up icon with number
        html += '<i class="fa fa-thumbs-up fa-lg"></i> ' + resource.seeded.length
      }
      html += '</div></div>'
    }
  }
  $('.output').empty().append(html)
}

function deletePlayer (id) {
  ss.rpc('admin.monitor.deletePlayer', id, function (err) {
    if (err) {
      var errorMessage = 'Error deleting player: ' + err
      console.log(errorMessage)
      apprise(errorMessage)
    } else {
      $('.player' + id).remove()
      apprise('Player deleted.')
    }
  })
}

function toggleGame (instance, bool) {
  ss.rpc('admin.monitor.toggleGame', instance, bool, function (err) {
    if (err) {
      var errorMessage = 'Error switching game: ' + err
      console.log(errorMessage)
      apprise(errorMessage)
    } else {
      if (bool) {
        apprise('The game is now active.')
      } else {
        apprise('The game is now inactive.')
      }
    }
  })
}

function showQuestions (instance) {
  var html = '<h2>Open-ended questions</h2>' +
             '<p><strong>Game name: <span class="color-darkblue">' + instance + '</span></strong></p>'

  for (var q = 0; q < allQuestions.length; q++) {
    var question = allQuestions[q]

    if (question.resource.questionType === 'open') {
      html += '<div class="question answer-toggle" data-instance="' + instance + '" data-resource="' + question.resource.id + '">'
      html += '<p data-resource="' + question.resource.id + '" class="mainQ level' + question.level + '">' + question.resource.question + '</p></div>'
    }
  }

  getAllAnswers(instance)
  $('.output').empty().append(html)
}

function getAllAnswers (instance) {
  ss.rpc('admin.monitor.getInstanceAnswers', instance, function (err, res) {
    if (err) {
      allAnswers = []
    } else if (res) {
      allAnswers = res.resourceResponses
    }
  })
}

function showQuestionAnswers (npc, instance, selector) {
  var html = ''
  var found = false
  var npcInt = parseInt(npc, 10)

  $('.question .answers').remove()

  for (var i = 0; i < allAnswers.length; i++) {
    if (allAnswers[i].resourceId === npcInt) {
      found = true
      html += '<p class="answers"><span class="player-name">' + allAnswers[i].name + ': </span>'
      html += '<span class="player-answer">' + allAnswers[i].answer + '</span></p>'
    }
  }
  if (!found) {
    html += '<p class="answers">There are no answers for this question yet.</p>'
  }

  $(selector).append(html)
}

function sortByLevel (a, b) {
  if (a.level < b.level) {
    return -1
  } else if (a.level > b.level) {
    return 1
  } else {
    return 0
  }
}

module.exports = {
  init: function () {
    $body = $(document.body)

    // NEED TO DO SOME SORT OF RPC CALL HERE TO MAKE SURE THIS NEVER CAN JUST HAPPEN UNLESS YOU HAVE THE RIGHT ROLE
    setupLoaders()
    setupMonitor()
  }
}