Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mapper-level icons and encouragement messages #1643

Merged
merged 1 commit into from
May 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
(function () {

'use strict';

/**
* @fileoverview This file provides methods for determining which messages
* to display to mappers to encourage them to get to the next mapping level
*/

angular
.module('taskingManager')
.controller('mapperEncouragementController', ['$scope', 'accountService', 'userService', 'settingsService', mapperEncouragementController])
.directive('mapperEncouragement', mapperEncouragementDirective);

/**
* Creates mapper-encouragement directive
* Example:
*
* <mapper-encouragement></mapper-encouragement>
*/
function mapperEncouragementDirective() {
var directive = {
restrict: 'EA',
templateUrl: 'app/components/mapper-encouragement/mapper-encouragement.html',
controller: 'mapperEncouragementController',
controllerAs: 'encouragementCtrl',
};

return directive;
}

function mapperEncouragementController($scope, accountService, userService, settingsService) {
var vm = this;
vm.account = {};
vm.mapperLevelIntermediate = 0;
vm.mapperLevelAdvanced = 0;
vm.mapperLevelsLoaded = false;

// Watch the accountService for changes and update when needed
$scope.$watch(function () {
return accountService.getAccount();
}, function (account) {
vm.account = account;

if (vm.account) {
// Fetch OSM details, which includes user's number of changesets
var osmDetailsPromise = userService.getOSMUserDetails(vm.account.username);
osmDetailsPromise.then(function (data) {
// On success, set the OSM account details for this user
vm.osmUserDetails = data;
});
}
}, true);

settingsService.getSettings().then(function (data) {
vm.mapperLevelIntermediate = data.mapperLevelIntermediate;
vm.mapperLevelAdvanced = data.mapperLevelAdvanced;
vm.mapperLevelsLoaded = true;
});

/**
* Returns true when all the needed data has been fetched
*/
vm.ready = function() {
return vm.account && vm.mapperLevelsLoaded && vm.osmUserDetails;
}

/**
* Returns the number of changesets completed at the logged-in user's
* current level (versus their total changeset count). Returns null if
* it can't be computed
*/
vm.completedIncrementalChangesets = function() {
if (vm.ready()) {
if (vm.account.mappingLevel === 'BEGINNER') {
return vm.osmUserDetails.changesetCount;
}
else if (vm.account.mappingLevel === 'INTERMEDIATE') {
return vm.osmUserDetails.changesetCount - vm.mapperLevelIntermediate;
}
else if (vm.account.mappingLevel === 'ADVANCED') {
return vm.osmUserDetails.changesetCount - vm.mapperLevelAdvanced;
}
}

return null;
};

/**
* Returns the incremental number of changesets required to advance to
* the next level. Returns null if it can't be computed or user is
* already an advanced mapper
*/
vm.requiredIncrementalChangesets = function() {
if (vm.ready()) {
if (vm.account.mappingLevel === 'BEGINNER') {
return vm.mapperLevelIntermediate;
}
else if (vm.account.mappingLevel === 'INTERMEDIATE') {
return vm.mapperLevelAdvanced - vm.mapperLevelIntermediate;
}
}

return null;
};

/**
* Computes the percentage mapping progress of the logged-in user needed
* to advance to the next level (i.e. 90% of the way there). Returns
* null if it can't be computed or if the user is already an advanced
* mapper and thus can't advance any further
*/
vm.mappingAdvancementProgress = function() {
if (vm.ready() && vm.account.mappingLevel !== 'ADVANCED') {
return vm.completedIncrementalChangesets() / vm.requiredIncrementalChangesets();
}

return null;
};

/**
* Determines if the logged-in user is at least 90% of the way to the
* next mapping level
*/
vm.isCloseToAdvancement = function() {
return vm.mappingAdvancementProgress() >= 0.9;
};

/**
* Determines if the logged-in user is at least halfway to the next
* mapping level
*/
vm.isHalfwayToAdvancement = function() {
return vm.mappingAdvancementProgress() >= 0.5;
};

/**
* Determines if the logged-in user has recently been promoted to a new
* mapping level (is less than 10% of the way to the next one)
*/
vm.isNewlyPromoted = function() {
return vm.mappingAdvancementProgress() < 0.1;
};

/**
* Determines if the logged-in user has ever mapped
*/
vm.hasMapped = function() {
return vm.account && vm.account.tasksMapped > 0;
};

/**
* Determines if the logged-in user has ever performed validation
*/
vm.hasValidated = function() {
return vm.account &&
vm.account.tasksValidated > 0 || vm.account.tasksInvalidated > 0;
};
}
})();
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<div ng-show="encouragementCtrl.ready()" class="mapper-encouragement">
<div ng-switch="encouragementCtrl.account.mappingLevel">
<div ng-switch-when="BEGINNER">
<div ng-if="encouragementCtrl.isCloseToAdvancement()"
class="mapper-encouragement__message">
{{ "You've almost reached intermediate mapper!" | translate }}
</div>
<div ng-if="!encouragementCtrl.isCloseToAdvancement()">
<div ng-if="encouragementCtrl.isHalfwayToAdvancement()"
class="mapper-encouragement__message">
{{ "You're over halfway to becoming an intermediate mapper!" | translate }}
</div>
<div ng-if="!encouragementCtrl.isHalfwayToAdvancement() && encouragementCtrl.hasMapped()"
class="mapper-encouragement__message">
{{ "You're on your way to becoming an intermediate mapper!" | translate }}
</div>
</div>
</div>

<div ng-switch-when="INTERMEDIATE">
<div ng-if="encouragementCtrl.isCloseToAdvancement()"
class="mapper-encouragement__message">
{{ "You've almost reached advanced mapper!" | translate }}
</div>
<div ng-if="!encouragementCtrl.isCloseToAdvancement()">
<div ng-if="encouragementCtrl.isHalfwayToAdvancement()"
class="mapper-encouragement__message">
{{ "You're over halfway to becoming an advanced mapper!" | translate }}
</div>
<div ng-if="!encouragementCtrl.isHalfwayToAdvancement()">
<div ng-if="encouragementCtrl.isNewlyPromoted()"
class="mapper-encouragement__message">
{{ "You've made intermediate mapper, keep it up! " | translate }}
</div>
<div ng-if="!encouragementCtrl.isNewlyPromoted()"
class="mapper-encouragement__message">
{{ "You're on your way to becoming an advanced mapper!" | translate }}
</div>
</div>
</div>
</div>

<div ng-switch-when="ADVANCED">
<div ng-if="!encouragementCtrl.hasValidated()"
class="mapper-encouragement__message">
<p>
{{ "You're an advanced mapper! Next," | translate }}
<a href="https://www.missingmaps.org/validate">
{{ "learn how to validate!" | translate }}
</a>
</p>
</div>
<div ng-if="encouragementCtrl.hasValidated()"
class="mapper-encouragement__message">
{{ "Keep up the validation! We need experts like you to help!" | translate }}
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
(function () {

'use strict';

/**
* @fileoverview This file provides a mapper-level indicator directive, by default
* for the logged in user, but also allows passing explicit username and level attributes
* for the indicator (as well as an optional label flag to show a description of the
* mapper level next to the indicator icon).
*/

angular
.module('taskingManager')
.controller('mapperLevelIndicatorController', ['$scope', '$location', 'accountService', mapperLevelIndicatorController])
.directive('mapperLevelIndicator', mapperLevelIndicatorDirective);

/**
* Creates mapper-level-indicator directive
* Example:
*
* <mapper-level-indicator></mapper-level-indicator>
*/
function mapperLevelIndicatorDirective() {

var directive = {
restrict: 'EA',
templateUrl: 'app/components/mapper-level-indicator/mapper-level-indicator.html',
controller: 'mapperLevelIndicatorController',
controllerAs: 'mapperLevelCtrl',
bindToController: {
label: '@', // show descriptive label next to the indicator icon
level: '@', // explicitly specify a mapping level for the indicator
username: '@', // explicitly specify username for indicator
},
};

return directive;
}

function mapperLevelIndicatorController($scope, $location, accountService) {

var vm = this;
vm.account = {};

// Watch the accountService for changes and update when needed
$scope.$watch(function () {
return accountService.getAccount();
}, function (account) {
vm.account = account;
}, true);

/**
* Get the mapper level for this indicator, which defaults to the
* logged-in user's level, but can be overriden if a level attribute
* was explicitly specified
*/
vm.mapperLevel = function() {
if (vm.level) {
return vm.level;
}
else if (vm.account) {
return vm.account.mappingLevel;
}
else {
return null;
}
};

/**
* Navigate to the user's profile
*/
vm.goToProfile = function () {
var username = vm.username ? vm.username : vm.account.username;
$location.path('user/' + username);
};
}
})();
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div ng-if="mapperLevelCtrl.mapperLevel()"
class="mapper-level-indicator {{ mapperLevelCtrl.mapperLevel() | lowercase }}">
<span class="mapper-level-indicator__icon fa fa-trophy" ng-click="mapperLevelCtrl.goToProfile()"
title="{{ mapperLevelCtrl.mapperLevel() | lowercase | translate }} {{ 'mapper' | translate }}"></span>
<span ng-if="mapperLevelCtrl.label" class="mapper-level-indicator__label">
{{ mapperLevelCtrl.mapperLevel() | lowercase | translate }} {{ 'Mapper' | translate }}
</span>
</div>
1 change: 1 addition & 0 deletions client/app/home/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ <h1 class="section__title">
{{ 'Map a Task for People in Need' | translate }}
</h1>
<p class='centered'>{{ 'Join coordinated humanitarian mapping projects by taking a task and mapping a part of the world in' | translate }} <a href="https://www.openstreetmap.org">OpenStreetMap</a>{{', the free and editable map of the world. Communities, organizations and governments worldwide have access to these maps to address local development challenges and aid disaster response. You can join thousands of others to map' | translate}} <a href="https://www.openstreetmap.org">OpenStreetMap</a> {{ 'and support these communities in need.' | translate }}</p>
<mapper-encouragement></mapper-encouragement>
<a class="button button--outline--white" role="button"
href="/contribute"><span>{{ 'Start Mapping' | translate }}</span></a>
</div>
Expand Down
11 changes: 9 additions & 2 deletions client/app/profile/profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,15 @@ <h1 class="section__title">
<div class="inner">
<div class="profile-container">
<div class="details">
<div>
<h4>{{ profileCtrl.username }}'s {{ 'Progress' | translate }}</h4>
<div class="mapping-progress">
<h4>
<span class="header">{{ profileCtrl.username }}'s {{ 'Progress' | translate }}</span>
<mapper-level-indicator ng-if="profileCtrl.userDetails.mappingLevel"
username="{{ profileCtrl.username }}"
level="{{ profileCtrl.userDetails.mappingLevel }}"
label="true"></mapper-level-indicator>
</h4>
<mapper-encouragement></mapper-encouragement>
<div ng-show="profileCtrl.mapperLevelIntermediate > profileCtrl.osmUserDetails.changesetCount">
<span class="label">{{ profileCtrl.mapperLevelIntermediate - profileCtrl.osmUserDetails.changesetCount }} {{ 'OSM changeset(s) to intermediate mapper' | translate }}</span>
<uib-progressbar value="profileCtrl.osmUserDetails.changesetCount" max="profileCtrl.mapperLevelIntermediate"></uib-progressbar>
Expand Down
16 changes: 16 additions & 0 deletions client/assets/styles/sass/_landingpage.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@
padding-top: 5rem;
padding-bottom: 5rem;
}
.mapper-encouragement__message {
padding: 0 0.5em 0.5em 0.5em;
color: #fff;
text-align: center;
font-size: 1.5em;
font-weight: $base-font-regular;

p {
margin: 0 auto;
}

a {
color: #fff;
font-weight: $base-font-bold;
}
}
}

/* ==========================================================================
Expand Down
9 changes: 9 additions & 0 deletions client/assets/styles/sass/_mapper_encouragement.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.mapper-encouragement {
padding-bottom: 0.5em;
font-size: 1.2em;
font-weight: $base-font-bold;

p {
margin-bottom: 0;
}
}
26 changes: 26 additions & 0 deletions client/assets/styles/sass/_mapperlevel.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.mapper-level-indicator {
display: flex;
align-items: center;

&.beginner {
color: $bronze;
}

&.intermediate {
color: $silver;
}

&.advanced {
color: $gold;
}

&__icon {
font-size: 2em;
}

&__label {
margin-left: 1rem;
text-transform: capitalize;
font-weight: $base-font-regular;
}
}
Loading