Commit ee0034e29eb08a5c9c634ea79c06515a39b0c65f

Authored by Adabriand Furtado
1 parent 9de8d912
Exists in master

Volunteers and Ranking section integrated with PyBossa API

assets/css/base.css
... ... @@ -12,7 +12,7 @@
12 12  
13 13 html, body {
14 14 font-family: 'Roboto', 'Open Sans', sans-serif;
15   - color: #000000;
  15 + color: #2d2d2d;
16 16 }
17 17  
18 18 img {
... ... @@ -34,28 +34,6 @@ img {
34 34 background-color: #337ab7;
35 35 }
36 36  
37   -.wl-section-title {
38   - position: absolute;
39   - top: -15px;
40   - font-size: 14px;
41   - font-weight: bold;
42   - color: #ffffff;
43   - text-transform: uppercase;
44   - text-align: center;
45   - font-family: 'Oswald';
46   - z-index: 1;
47   - width: 100%;
48   - margin: 0 auto;
49   -}
50   -
51   -.wl-section-title .title {
52   - padding: 5px 0;
53   - background-color: #0f78a7;
54   - -webkit-border-radius: 6px;
55   - -moz-border-radius: 6px;
56   - border-radius: 6px;
57   -}
58   -
59 37 /* Header */
60 38 #wl-header {
61 39 position: relative;
... ... @@ -151,6 +129,36 @@ img {
151 129 cursor: pointer;
152 130 }
153 131  
  132 +/* Sections */
  133 +.wl-section-title {
  134 + position: absolute;
  135 + top: -15px;
  136 + font-size: 14px;
  137 + font-weight: bold;
  138 + color: #ffffff;
  139 + text-transform: uppercase;
  140 + text-align: center;
  141 + font-family: 'Oswald';
  142 + z-index: 1;
  143 + width: 100%;
  144 + margin: 0 auto;
  145 +}
  146 +
  147 +.wl-section-title .title {
  148 + padding: 5px 0;
  149 + background-color: #0f78a7;
  150 + -webkit-border-radius: 6px;
  151 + -moz-border-radius: 6px;
  152 + border-radius: 6px;
  153 +}
  154 +
  155 +.wl-section-description {
  156 + margin-top: 90px;
  157 + font-size: 14px;
  158 + line-height: 24px;
  159 + text-align: center;
  160 +}
  161 +
154 162 /* Presentation Section */
155 163 #wl-presentation-video {
156 164 height: 100vh;
... ... @@ -191,13 +199,6 @@ img {
191 199 z-index: 1;
192 200 }
193 201  
194   -.wl-overview-description {
195   - margin-top: 90px;
196   - font-size: 14px;
197   - line-height: 24px;
198   - text-align: center;
199   -}
200   -
201 202 .wl-overview-progress-wrapper {
202 203 padding-bottom: 20px;
203 204 }
... ... @@ -362,11 +363,116 @@ img {
362 363 width: 100%;
363 364 }
364 365  
  366 +/* Signs and Ranking Section */
  367 +#wl-signs-and-ranking {
  368 + position: relative;
  369 + z-index: 1;
  370 + background: #ffffff;
  371 + height: 100vh;
  372 +}
  373 +
  374 +.wl-signs-and-ranking-container {
  375 + display: flex;
  376 + flex-direction: row;
  377 + flex-wrap: wrap;
  378 +}
  379 +
  380 +.wl-signs-and-ranking-wrapper {
  381 + flex: 1;
  382 + position: relative;
  383 + min-width: 330px;
  384 +}
  385 +
  386 +.wl-signs-and-ranking-wrapper .wl-section-title {
  387 + padding: 0 15px;
  388 +}
  389 +
  390 +.wl-signs-container {
  391 + display: flex;
  392 + flex-wrap: wrap;
  393 + margin-top: 30px;
  394 +}
  395 +
  396 +.wl-signs-wrapper {
  397 + flex: 1 0 33%;
  398 + padding: 3px;
  399 +}
  400 +
  401 +.wl-ranking-header-wrapper {
  402 + padding-left: 0;
  403 + padding-right: 0;
  404 + cursor: pointer;
  405 +}
  406 +
  407 +.wl-ranking-header-wrapper:first-child {
  408 + padding-left: 30px;
  409 +}
  410 +
  411 +.wl-ranking-header-wrapper:last-child {
  412 + padding-right: 15px;
  413 +}
  414 +
  415 +.wl-ranking-header-wrapper:last-child .title {
  416 + border-right: 0;
  417 +}
  418 +
  419 +.wl-ranking-header {
  420 + text-align: center;
  421 + line-height: 35px;
  422 + border-bottom: 1px solid #ccc;
  423 +}
  424 +
  425 +.wl-ranking-header.-active {
  426 + border-bottom: 1px solid #bb6a1a;
  427 +}
  428 +
  429 +.wl-ranking-header .title {
  430 + margin-bottom: 10px;
  431 + border-right: 1px solid #ccc;
  432 +}
  433 +
  434 +.wl-ranking-header.-active .title {
  435 + color: #bb6a1a;
  436 + font-weight: bold;
  437 +}
  438 +
  439 +.wl-ranking-container {
  440 + padding: 15px;
  441 + color: #bb6a1a;
  442 +}
  443 +
  444 +.wl-rank {
  445 + padding-bottom: 20px;
  446 +}
  447 +
  448 +.star-wrapper {
  449 + position: absolute;
  450 + margin-top: -2px;
  451 + height: 14px;
  452 +}
  453 +
  454 +.position-wrapper {
  455 + padding-left: 50px;
  456 +}
  457 +
365 458 /* Responsiveness */
366 459 @media screen and (min-width: 768px) {
  460 + .wl-section-title {
  461 + top: -22px;
  462 + font-size: 24px;
  463 + }
  464 + .wl-section-title .title {
  465 + width: 360px;
  466 + margin: 0 auto;
  467 + padding: 6px 0;
  468 + }
  469 +
  470 + /* Overview */
367 471 #wl-overview {
368 472 height: 100vh;
369 473 }
  474 +
  475 + /* Features */
370 476 #wl-features {
371 477 height: 100vh;
372 478 }
... ... @@ -375,14 +481,20 @@ img {
375 481 padding-top: 0;
376 482 padding-bottom: 0;
377 483 }
378   - .wl-section-title {
379   - top: -30px;
380   - font-size: 26px;
  484 +
  485 + /* Volunteers */
  486 +
  487 + /* Signs and Ranking */
  488 + .wl-signs-and-ranking-wrapper .wl-section-title .title {
  489 + width: 100%;
381 490 }
382   - .wl-section-title .title {
383   - width: 360px;
384   - margin: 0 auto;
385   - padding: 12px 0;
  491 +
  492 + .wl-signs-and-ranking-wrapper .wl-section-title {
  493 + padding: 0 50px;
  494 + }
  495 +
  496 + .wl-signs-and-ranking-wrapper {
  497 + padding: 0 15px;
386 498 }
387 499 }
388 500  
... ...
assets/img/bronze-star-icon.png 0 → 100644

279 Bytes

assets/img/gold-star-icon.png 0 → 100644

278 Bytes

assets/img/sign-placeholder.png 0 → 100644

15.1 KB

assets/img/silver-star-icon.png 0 → 100644

277 Bytes

assets/js/main.controller.js
1 1 (function () {
2 2 'use strict';
3 3  
4   - angular.module('wikilibras').controller('wikilibrasCtrl', ['$scope', function ($scope) {
5   - var baseUrl = 'assets/img/user-avatar-';
6   - $scope.avatars = [];
7   - for (var i = 0; i < 50; i++) {
8   - $scope.avatars.push({ url: baseUrl + getRandomInt(1, 5) + '.png'});
9   - }
10   - function getRandomInt(min, max) {
11   - return Math.floor(Math.random() * (max - min + 1)) + min;
12   - }
13   - }]);
  4 + angular.module('wikilibras').controller('wikilibrasCtrl', ['$scope', function ($scope) {}]);
14 5 }());
15 6 \ No newline at end of file
... ...
assets/js/main.module.js
1 1 (function () {
2 2 'use strict';
3 3  
4   - angular.module('wikilibras', ['wikilibras.progress', 'duScroll', 'angularMoment']).value('duScrollOffset', 70);
  4 + angular.module('wikilibras', ['wikilibras.progress', 'wikilibras.ranking', 'wikilibras.volunteers', 'duScroll', 'angularMoment']).value('duScrollOffset', 70);
5 5 }());
6 6 \ No newline at end of file
... ...
assets/js/progress/progress.controller.js
... ... @@ -11,6 +11,7 @@
11 11 progressService.getProjectsProgressData().then(function(response) {
12 12 angular.forEach(response, function(progress) {
13 13 var projectProgress = $scope.progress[progress.short_name];
  14 + if (!projectProgress || typeof projectProgress === "undefined") return;
14 15 projectProgress.n_tasks = progress.n_tasks;
15 16 projectProgress.n_task_runs = progress.n_task_runs;
16 17 projectProgress.n_completed_tasks = progress.n_completed_tasks;
... ...
assets/js/progress/progress.service.js
1 1 (function () {
2 2 'use strict';
3 3  
4   - angular.module('wikilibras.progress').service("progressService", ['$http', '$q', function ($http, $q) {
5   - var API_ENDPOINT = 'http://localhost/pybossa/api';
6   - var PROJECTS_PROGRESS_API_URL = API_ENDPOINT + '/projects_progress';
7   - var PROJECTS_GOALS_URL = 'conf/goals.json';
  4 + angular.module('wikilibras.progress').service("progressService", ['$http', function ($http) {
  5 + var PROJECT_CONF_URL = 'conf/app-conf.json';
  6 + var PROJECTS_PROGRESS_ENDPOINT = '/api/projects_progress';
8 7  
9   - function accesGoalsData(goals, projectName, param) {
  8 + function accessGoalsData(goals, projectName, param) {
10 9 var projectGoals = goals[projectName];
11 10 if (!projectGoals || typeof projectGoals === 'undefined') return '';
12 11 var goal = projectGoals[param];
... ... @@ -16,17 +15,19 @@
16 15  
17 16 return {
18 17 getProjectsProgressData: function() {
19   - var requestProgress = $http.get(PROJECTS_PROGRESS_API_URL);
20   - var requestGoals = $http.get(PROJECTS_GOALS_URL);
21   - return $q.all([requestProgress, requestGoals]).then(function(responses) {
22   - var responseProgress = responses[0].data;
23   - var responseGoals = responses[1].data;
24   - angular.forEach(responseProgress, function(progress) {
25   - progress['goal_n_tasks'] = accesGoalsData(responseGoals, progress.short_name,'goal_n_tasks');
26   - progress['goal_deadline'] = moment(accesGoalsData(responseGoals, progress.short_name,'goal_deadline'), "DD/MM/YYYY");
27   - progress['last_activity'] = moment(progress['last_activity']);
  18 + return $http.get(PROJECT_CONF_URL).then(function(response) {
  19 + var baseApiUrl = response.data.pybossa_url;
  20 + var responseGoals = response.data.goals;
  21 +
  22 + return $http.get(baseApiUrl + PROJECTS_PROGRESS_ENDPOINT).then(function(response) {
  23 + var responseProgress = response.data;
  24 + angular.forEach(responseProgress, function(progress) {
  25 + progress['goal_n_tasks'] = accessGoalsData(responseGoals, progress.short_name,'goal_n_tasks');
  26 + progress['goal_deadline'] = moment(accessGoalsData(responseGoals, progress.short_name,'goal_deadline'), "DD/MM/YYYY");
  27 + progress['last_activity'] = moment(progress['last_activity']);
  28 + });
  29 + return responseProgress;
28 30 });
29   - return responseProgress;
30 31 });
31 32 }
32 33 };
... ...
assets/js/ranking/ranking.controller.js 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +(function () {
  2 + 'use strict';
  3 +
  4 + angular.module('wikilibras.ranking').controller('rankingCtrl', ['$scope', 'rankingService', function ($scope, rankingService) {
  5 + $scope.activeTab = 0;
  6 + $scope.rankingData = {};
  7 +
  8 + $scope.setActiveTab = function(tab) {
  9 + $scope.activeTab = tab;
  10 + };
  11 +
  12 + rankingService.getRankingData().then(function(response) {
  13 + $scope.rankingData = response;
  14 + console.log(response);
  15 + });
  16 + }]);
  17 +}());
0 18 \ No newline at end of file
... ...
assets/js/ranking/ranking.module.js 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +(function () {
  2 + 'use strict';
  3 +
  4 + angular.module('wikilibras.ranking', []);
  5 +}());
0 6 \ No newline at end of file
... ...
assets/js/ranking/ranking.service.js 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +(function () {
  2 + 'use strict';
  3 +
  4 + angular.module('wikilibras.ranking').service("rankingService", ['$http', '$q', function ($http, $q) {
  5 + var PROJECT_CONF_URL = 'conf/app-conf.json';
  6 + var RANKING_ENDPOINT = '/api/leaderboard?limit=20';
  7 +
  8 + return {
  9 + getRankingData: function() {
  10 + return $http.get(PROJECT_CONF_URL).then(function(response) {
  11 + var baseApiUrl = response.data.pybossa_url;
  12 + return $http.get(baseApiUrl + RANKING_ENDPOINT).then(function(response) {
  13 + console.log(response);
  14 + return response.data;
  15 + });
  16 + });
  17 + }
  18 + };
  19 + }]);
  20 +}());
0 21 \ No newline at end of file
... ...
assets/js/volunteers/volunteers.controller.js 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +(function () {
  2 + 'use strict';
  3 +
  4 + angular.module('wikilibras.volunteers').controller('volunteersCtrl', ['$scope', 'volunteersService', function ($scope, volunteersService) {
  5 + $scope.volunteersData = {};
  6 + volunteersService.getVolunteersData().then(function(response) {
  7 + $scope.volunteersData = response;
  8 + });
  9 + }]);
  10 +}());
0 11 \ No newline at end of file
... ...
assets/js/volunteers/volunteers.module.js 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +(function () {
  2 + 'use strict';
  3 +
  4 + angular.module('wikilibras.volunteers', []);
  5 +}());
0 6 \ No newline at end of file
... ...
assets/js/volunteers/volunteers.service.js 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +(function () {
  2 + 'use strict';
  3 +
  4 + angular.module('wikilibras.volunteers').service("volunteersService", ['$http', function ($http) {
  5 + var PROJECT_CONF_URL = 'conf/app-conf.json';
  6 + var VOLUNTEERS_ENDPOINT = '/api/user?limit=50';
  7 +
  8 + return {
  9 + getVolunteersData: function() {
  10 + return $http.get(PROJECT_CONF_URL).then(function(response) {
  11 + var baseApiUrl = response.data.pybossa_url;
  12 + return $http.get(baseApiUrl + VOLUNTEERS_ENDPOINT).then(function(response) {
  13 + var volunteersData = response.data;
  14 + angular.forEach(volunteersData, function(data) {
  15 + data.info['avatar_url'] = data.info.container && data.info.avatar? baseApiUrl + '/uploads/' + data.info.container + '/' + data.info.avatar : '';
  16 + });
  17 + console.log(volunteersData);
  18 + return volunteersData;
  19 + });
  20 + });
  21 + }
  22 + };
  23 + }]);
  24 +}());
0 25 \ No newline at end of file
... ...
assets/templates/sections.html
... ... @@ -21,7 +21,7 @@
21 21 </div>
22 22 </div>
23 23 </div>
24   - <div class="col-xs-12 wl-overview-description">
  24 + <div class="col-xs-12 wl-section-description">
25 25 <p>Lorem Ipsum é simplesmente uma simulação de texto da indústria tipográfica e de impressos, e vem
26 26 sendo utilizado desde o século XVI, quando um impressor desconhecido pegou uma bandeja de tipos
27 27 e os embaralhou para fazer um livro de modelos de tipos. Lorem Ipsum sobreviveu não só a cinco
... ... @@ -186,7 +186,7 @@
186 186 </div>
187 187 </div>
188 188 </section>
189   -<section id="wl-volunteers">
  189 +<section id="wl-volunteers" ng-controller="volunteersCtrl">
190 190 <div class="container-fluid">
191 191 <div class="row">
192 192 <div class="col-xs-12 wl-section-title">
... ... @@ -194,8 +194,8 @@
194 194 colaborando</div>
195 195 </div>
196 196 <div class="col-xs-12 wl-volunteers-container">
197   - <div ng-repeat="avatar in avatars" class="wl-volunteers-wrapper">
198   - <img ng-src="{{ avatar.url }}">
  197 + <div ng-repeat="volunteers in volunteersData" class="wl-volunteers-wrapper" ng-if="volunteers.info.avatar_url !== ''">
  198 + <img ng-src="{{ volunteers.info.avatar_url }}">
199 199 </div>
200 200 <div ng-repeat="avatar in avatars"
201 201 ng-if="avatars.length % 10 === 0? false: $index <= avatars.length - avatars.length % 10"
... ... @@ -204,4 +204,149 @@
204 204 </div>
205 205 </div>
206 206 </div>
  207 +</section>
  208 +<section id="wl-signs-and-ranking">
  209 + <div class="container-fluid">
  210 + <div class="row">
  211 + <div class="col-xs-12 wl-signs-and-ranking-container">
  212 + <div class="wl-signs-and-ranking-wrapper">
  213 + <div class="wl-section-title">
  214 + <div class="title">sinais
  215 + construídos
  216 + </div>
  217 + </div>
  218 + <div class="wl-section-description">
  219 + <p>Lorem Ipsum é simplesmente uma simulação de texto da indústria tipográfica e de impressos, e vem sendo utilizado desde o século XVI.</p>
  220 + </div>
  221 + <div class="wl-signs-container">
  222 + <div class="wl-signs-wrapper" ng-repeat="i in [1,2,3,4,5,6,7,8,9]">
  223 + <img src="assets/img/sign-placeholder.png">
  224 + </div>
  225 + </div>
  226 + </div>
  227 + <div class="wl-signs-and-ranking-wrapper" ng-controller="rankingCtrl">
  228 + <div class="wl-section-title">
  229 + <div class="title">ranking
  230 + dos colaborandores
  231 + </div>
  232 + </div>
  233 + <div class="wl-section-description"></div>
  234 + <div class="row">
  235 + <div class="col-xs-3 wl-ranking-header-wrapper" ng-click="setActiveTab(0)">
  236 + <div class="wl-ranking-header" ng-class="{'-active': activeTab === 0}">
  237 + <div class="title">
  238 + Sinais construídos
  239 + </div>
  240 + </div>
  241 + </div>
  242 + <div class="col-xs-3 wl-ranking-header-wrapper" ng-click="setActiveTab(1)">
  243 + <div class="wl-ranking-header" ng-class="{'-active': activeTab === 1}">
  244 + <div class="title">
  245 + Sinais corrigidos
  246 + </div>
  247 + </div>
  248 + </div>
  249 + <div class="col-xs-3 wl-ranking-header-wrapper" ng-click="setActiveTab(2)">
  250 + <div class="wl-ranking-header" ng-class="{'-active': activeTab === 2}">
  251 + <div class="title">
  252 + Sinais avaliados
  253 + </div>
  254 + </div>
  255 + </div>
  256 + <div class="col-xs-3 wl-ranking-header-wrapper" ng-click="setActiveTab(3)">
  257 + <div class="wl-ranking-header" ng-class="{'-active': activeTab === 3}">
  258 + <div class="title">
  259 + Vídeos enviados
  260 + </div>
  261 + </div>
  262 + </div>
  263 + </div>
  264 + <div ng-show="activeTab == 0" class="wl-ranking-container">
  265 + <div class="row">
  266 + <div class="col-xs-6" ng-repeat="user in rankingData.wikilibras">
  267 + <div class="wl-rank">
  268 + <div class="row">
  269 + <div class="col-xs-4">
  270 + <div class="star-wrapper">
  271 + <img ng-if="[0,1,2].indexOf($index) !== -1" ng-src="assets/img/{{$index === 0? 'gold':($index === 1? 'silver': 'bronze')}}-star-icon.png">
  272 + </div>
  273 + <div class="position-wrapper">
  274 + {{ $index+1 }}.
  275 + </div>
  276 + </div>
  277 + <div class="col-xs-8 wl-ranked-volunteer">
  278 + {{ user.name }}
  279 + </div>
  280 + </div>
  281 + </div>
  282 + </div>
  283 + </div>
  284 + </div>
  285 + <div ng-show="activeTab === 1" class="wl-ranking-container">
  286 + <div class="row">
  287 + <div class="col-xs-6" ng-repeat="user in rankingData.corretor_sinais">
  288 + <div class="wl-rank">
  289 + <div class="row">
  290 + <div class="col-xs-4">
  291 + <div class="star-wrapper">
  292 + <img ng-if="[0,1,2].indexOf($index) !== -1" ng-src="assets/img/{{$index === 0? 'gold':($index === 1? 'silver': 'bronze')}}-star-icon.png">
  293 + </div>
  294 + <div class="position-wrapper">
  295 + {{ $index+1 }}.
  296 + </div>
  297 + </div>
  298 + <div class="col-xs-8 wl-ranked-volunteer">
  299 + {{ user.name }}
  300 + </div>
  301 + </div>
  302 + </div>
  303 + </div>
  304 + </div>
  305 + </div>
  306 + <div ng-show="activeTab === 2" class="wl-ranking-container">
  307 + <div class="row">
  308 + <div class="col-xs-6" ng-repeat="user in rankingData.validador_sinais">
  309 + <div class="wl-rank">
  310 + <div class="row">
  311 + <div class="col-xs-4">
  312 + <div class="star-wrapper">
  313 + <img ng-if="[0,1,2].indexOf($index) !== -1" ng-src="assets/img/{{$index === 0? 'gold':($index === 1? 'silver': 'bronze')}}-star-icon.png">
  314 + </div>
  315 + <div class="position-wrapper">
  316 + {{ $index+1 }}.
  317 + </div>
  318 + </div>
  319 + <div class="col-xs-8 wl-ranked-volunteer">
  320 + {{ user.fullname }}
  321 + </div>
  322 + </div>
  323 + </div>
  324 + </div>
  325 + </div>
  326 + </div>
  327 + <div ng-show="activeTab === 3" class="wl-ranking-container">
  328 + <div class="row">
  329 + <div class="col-xs-6" ng-repeat="i in [0,1,2,3,4,5,6,7,8,9]">
  330 + <div class="wl-rank">
  331 + <div class="row">
  332 + <div class="col-xs-4">
  333 + <div class="star-wrapper">
  334 + <img ng-if="[0,1,2].indexOf($index) !== -1" ng-src="assets/img/{{$index === 0? 'gold':($index === 1? 'silver': 'bronze')}}-star-icon.png">
  335 + </div>
  336 + <div class="position-wrapper">
  337 + {{ $index+1 }}.
  338 + </div>
  339 + </div>
  340 + <div class="col-xs-8 wl-ranked-volunteer">
  341 + {{ 'Teste ' + (i + 1) }}
  342 + </div>
  343 + </div>
  344 + </div>
  345 + </div>
  346 + </div>
  347 + </div>
  348 + </div>
  349 + </div>
  350 + </div>
  351 + </div>
207 352 </section>
208 353 \ No newline at end of file
... ...
conf/app-conf.json 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +{
  2 + "pybossa_url": "http://localhost/pybossa",
  3 + "goals": {
  4 + "wikilibras": {
  5 + "goal_n_tasks": 20,
  6 + "goal_deadline": "30/09/2016"
  7 + },
  8 + "corretor_sinais": {
  9 + "goal_n_tasks": 30,
  10 + "goal_deadline": "29/09/2016"
  11 + },
  12 + "validador_sinais": {
  13 + "goal_n_tasks": 40,
  14 + "goal_deadline": "28/09/2016"
  15 + }
  16 + }
  17 +}
0 18 \ No newline at end of file
... ...
conf/goals.json
... ... @@ -1,14 +0,0 @@
1   -{
2   - "wikilibras": {
3   - "goal_n_tasks": 20,
4   - "goal_deadline": "30/09/2016"
5   - },
6   - "corretor_sinais": {
7   - "goal_n_tasks": 30,
8   - "goal_deadline": "29/09/2016"
9   - },
10   - "validador_sinais": {
11   - "goal_n_tasks": 40,
12   - "goal_deadline": "28/09/2016"
13   - }
14   -}
15 0 \ No newline at end of file
index.html
... ... @@ -28,6 +28,12 @@
28 28 <script src="assets/js/libs/moment.min.js"></script>
29 29 <script src="assets/js/libs/angular-moment.min.js"></script>
30 30  
  31 + <script src="assets/js/volunteers/volunteers.module.js"></script>
  32 + <script src="assets/js/volunteers/volunteers.service.js"></script>
  33 + <script src="assets/js/volunteers/volunteers.controller.js"></script>
  34 + <script src="assets/js/ranking/ranking.module.js"></script>
  35 + <script src="assets/js/ranking/ranking.service.js"></script>
  36 + <script src="assets/js/ranking/ranking.controller.js"></script>
31 37 <script src="assets/js/progress/progress.module.js"></script>
32 38 <script src="assets/js/progress/progress.service.js"></script>
33 39 <script src="assets/js/progress/progress.controller.js"></script>
... ...