Skip to content

2. Frontend Development

Liwei edited this page Jun 14, 2017 · 44 revisions

Page Outline

Frontend Package: https://github.com/OpenISDM/platform-client
All these features below could be demonstrated by choosing frontend branch "ushahidi_plus" and backend branch "ushahidi_plus".


Add Location Button on Beginning Map

  • Revised File:
    ./platform-client/app/common/services/maps.js
    ./platform-client/app/main/posts/views/post-view-map.directive.js
  • Explanation:
    The file "map.js" includes all the functions and settings while creating a map in the website. So we copied and renamed the function "createMap()" to be "createMapIndex()". The function "createMapIndex()" would then be used for creating the beginning map. Following shows the code of the location button.
function createMapIndex(element) { 
...
var userlocate = L.control.locate({
    strings: {
        title: 'Show me where I am.'
    },
    position: 'bottomleft',
    //keepCurrentZoomLevel: true,
    circleStyle: {
        color: '#FF0000',
        fillColor: '#FF0000'
    },
    markerStyle: {
        color: '#FF0000',
        fillColor: '#FF0000'
    },
    locateOptions: {
        maxZoom: 15
    },
}).addTo(map);
userlocate = L.control.locate({
    keepCurrentZoomLevel: false, //keep the same zoom level
    showPopup: true
});
...
}

The file "post-view-map.directive.js" controls the map on the website index. In this file, we replaced "createMap()" to "createMapIndex()".

function activate() { 
...
var createMap = Maps.createMapIndex(element[0].querySelector('#map'))
    .then(function (data) {
    map = data;
});
...
}

Create a New Page on Side-Bar

  • New Folder:
    ./platform-client/app/main/intro/
    includes files: intro-module.js, intro-routes.js, intro.controller.js, intro.html
  • Revised Files:
    ./platform-client/app/main/main-module.js
    ./platform-client/app/common/directives/mode-bar/mode-bar.html
  • Explanation:
    Take TSER project for example. First, create a new folder "intro" and include all the files related to the introduction page. Then, include "intro-module.js" to "main-module.js".
angular.module('ushahidi.main', [
    'ushahidi.posts',
    'ushahidi.activity', 
    'ushahidi.intro', 
    'ushahidi.manage'
]);

require('./posts/posts-module.js');
require('./activity/activity-module.js');
require('./intro/intro-module.js');
require('./manage/manage-module.js');

The file "mode-bar.html" is related to the view of the side-bar. So finally, add a button of the introduction page on side-bar.

<li ng-class="{ active: activeMode === 'intro' }">
    <a ng-href="/intro" class="view-list">
        <svg class="iconic">
            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/img/iconic-sprite.svg#book"></use>
        </svg>
        <translate>views.intro</translate>
    </a>
</li>

Launch User Profile after Login

  • Revised Files:
    ./platform-client/app/common/auth/login.directive.js
  • Explanation:
    In file "login.directive.js", add the function "openProfile()". Also, execute "openProfile()" after successfully logging in.
function openProfile() {
    if ($scope.failed == false) {
        ModalService.openTemplate('<account-settings></account-settings>', '', false, false, true, true);
    }
}
function loginSubmit(email, password) {
    $scope.processing = true;
    Authentication
    .login(email, password)
    .then(finishedLogin, clearLoginForm)
//--------------------Open User Profile--------------------//
    .then(openProfile);
//---------------------------------------------------------//
}

Create a New Page on User Profile

  • New Files:
    ./platform-client/app/common/user-profile/vms-profile.directive.js
    ./platform-client/app/common/user-profile/vms-profile.html
  • Revised Files:
    ./platform-client/app/common/user-profile/user-profile-module.js
    ./platform-client/app/common/user-profile/account-settings.html
    ./platform-client/app/common/user-profile/account-settings.directive.js
  • Explanation:
    Take TSER project for example. First, create files "vms-profile.html" and "vms-profile.directive.js" for the new page on the user profile. Then, we should include "vms-profile.directive.js" in "user-profile-module.js".
angular.module('ushahidi.user-profile', [])
.directive('accountSettings', require('./account-settings.directive.js'))
.directive('userProfile', require('./user-profile.directive.js'))
.directive('notifications', require('./notifications.directive.js'))
.directive('vmsProfile', require('./vms-profile.directive.js')) // add new page "vms profile" on user profile
.directive('reportLocation', require('./report-location.directive.js')) // add location tool on user profile
;  

Files "account-settings.html" and "account-settings.directive.js" control the view and the setting of the tabs on the user profile. So first add a new tab for a new page in "account-settings.html".

...
<li ng-class="{'active': vmsprofile}">
    <a ng-click="showVMSProfile()" translate>
        user_profile.nav.vmsprofile
    </a>
</li>
...
<div class="modal-body">
    <user-profile ng-show="general"></user-profile>
    <notifications ng-show="notifications"></notifications>
    <vms-profile ng-show="vmsprofile"></vms-profile>
</div>

Then, add a new function for the event of clicking the tab of the new page.

scope.showVMSProfile = function () {
    scope.general = false;
    scope.notifications = false;
    scope.vmsprofile = true;
};  

Create a Post at User's Location After Login

  • New Files:
    ./platform-client/app/common/user-profile/report-location.html
    ./platform-client/app/common/user-profile/report-location.directive.js
  • Revised Files
    ./platform-client/app/common/user-profile/user-profile.html
    ./platform-client/app/common/user-profile/user-profile.directive.js
  • Explanation:
    This feature allows a user to create a post at his or her current location or update his or her previous location post. To provide location information, users could just mark a rough location on the small map or use the location button to find a more precise location. The files "report-location.html" and "report-location.directive.js" include the view and controllers of the small map on the user profile. To create a new location post or update a existing one, first, we need to check whether a user has already created a location post.
var reqBody = {
    "username": $rootScope.userEmail.toString(),
    "password": $rootScope.userPassword.toString(), 
    "grant_type": "password",
    "client_id": "ushahidiui",
    "client_secret": "35e7f0bca957836d05ca0492211b0ac707671261",
    "scope": "posts media forms api tags savedsearches sets users stats layers config messages notifications contacts roles permissions csv dataproviders"
};
var Req = {
    method: 'POST', 
    url: 'http://140.109.22.155:3333/oauth/token', 
    headers: {},
    data: JSON.stringify(reqBody)
};
//Get Ushahidi access token
$http(Req).then(
function(response) {
    $scope.userToken = response.data.token_type.toString() + ' ' + response.data.access_token.toString();
    var post_reqHead = {
        'Content-Type': 'application/json', 
        'Authorization': $scope.userToken
    };
    var post_Req = {
        method: 'GET', 
        url: 'http://140.109.22.155:3333/api/v3/posts?form=7&status=draft', 
        headers: post_reqHead,
    }; 
    //Check if user location post exists 
    $http(post_Req).then(
        function(response) {
        if (response.data.count==1) {
            console.log('!!! User Location Post Exists !!!');
            console.log('!!! Location Post ID: '+response.data.results[0].id+' !!!');
            $rootScope.userPostId = response.data.results[0].id;
        } else if (response.data.count==0) { 
            console.log('!!! User Location Post Does Not Exist !!!');
        } else {
            console.log('!!! The number of location posts is lager than 1 !!!'); 
        }
    }, 
    function(response) {$scope.userToken = response.data.token_type.toString() + ' ' + response.data.access_token.toString();
        var post_reqHead = {
            'Content-Type': 'application/json', 
            'Authorization': $scope.userToken
        };
        console.log('!!! Fail to check user location post !!!');
    }
    );
}, 
function(response) { 
    console.log('!!! Fail to get ushahidi access token !!!');
}
);

If the location post exists, we would get its ID number and update the new information to it. Following shows how to send a request to update an existing post.

var reqBody = {
    "username": $rootScope.userEmail.toString(),
    "password": $rootScope.userPassword.toString(), 
    "grant_type": "password",
    "client_id": "ushahidiui",
    "client_secret": "35e7f0bca957836d05ca0492211b0ac707671261",
    "scope": "posts media forms api tags savedsearches sets users stats layers config messages notifications contacts roles permissions csv dataproviders"
};
var Req = {
    method: 'POST', 
    url: 'http://140.109.22.155:3333/oauth/token', 
    headers: {},
    data: JSON.stringify(reqBody)
}; 
// Get Ushahidi User Access Token
$http(Req).then(
    function(response){
        $scope.userToken = response.data.token_type.toString() + ' ' + response.data.access_token.toString();
        var post_reqHead = {
            'Content-Type': 'application/json', 
            'Authorization': $scope.userToken
        };
        ...
        var post_Req = {
            method: 'PUT', 
            url: 'http://140.109.22.155:3333/api/v3/posts/'+$rootScope.userPostId.toString(), 
            headers: post_reqHead,
            data: JSON.stringify(post_reqBody)
        };
        // Update Post $scope.userToken = response.data.token_type.toString() + ' ' + response.data.access_token.toString();
        var post_reqHead = {
            'Content-Type': 'application/json', 
            'Authorization': $scope.userToken
        };
        $http(post_Req).then(
            function(response){
                $rootScope.userPostId = response.data.id;
                console.log('!!! Update Post '+$rootScope.userPostId+' !!!');
            }, 
            function(response){
                console.log('!!! Update Post Fail !!!');
            }
        );
    }, 
    function(response){
        console.log('!!! Get Ushahidi User Access Token Fail !!!');
    }
);

If the location post doesn't exist, we would create a new location post with the new information. Following shows how to send a request to create a post.

var reqBody = {
    "username": $rootScope.userEmail.toString(),
    "password": $rootScope.userPassword.toString(), 
    "grant_type": "password",
    "client_id": "ushahidiui",
    "client_secret": "35e7f0bca957836d05ca0492211b0ac707671261",
    "scope": "posts media forms api tags savedsearches sets users stats layers config messages notifications contacts roles permissions csv dataproviders"
};
var Req = {
    method: 'POST', 
    url: 'http://140.109.22.155:3333/oauth/token', 
    headers: {},
    data: JSON.stringify(reqBody)
};
// Get Ushahidi User Access Token
$http(Req).then(
    function(response) {
        $scope.userToken = response.data.token_type.toString() + ' ' + response.data.access_token.toString();
        var post_reqHead = {
            'Content-Type': 'application/json', 
            'Authorization': $scope.userToken
        }; 
        ...
        var post_Req = {
            method: 'POST', 
            url: 'http://140.109.22.155:3333/api/v3/posts', 
            headers: post_reqHead,
            data: JSON.stringify(post_reqBody)
        };
        // Create Post 
        $http(post_Req).then(
            function(response){
                $rootScope.userPostId = response.data.id;
                console.log('!!! Create Post '+$rootScope.userPostId+' !!!');
            }, 
            function(response){
                console.log('!!! Create Post Fail !!!');
            }
        );        
    }, 
...
);
  • Revised Files:
    ./platform-client/app/main/posts/views/mode-context-form-filter.html
  • Explanation:
    The pictures above show that users who are not project manager could only see their own location posts and project managers are allowed to see all the user location posts. So, in this example, we could first set the property of the survey "Management Map" to be "require posts be reviewed". This would allow only project managers could see all the user location posts. Second, we need to hide the survey "Management Map" when users log in and do not be recognized as project manager. So, in file "mode-context-form-filter.html", we add conditions in the survey loop to show "Management Map" while logging in as project manager.
<form class="survey-filter">
    <!-- survey loop -->
    <div class="survey-filter-checkbox init" ng-class="{ checked : (filters.form.indexOf(form.id) !== -1) }" ng-repeat="form in forms" dropdown>
        <!-- The form id of the survey "Management Map" is 7 -->
        <div ng-if="form.id == 7"> 
            <div ng-hide="!hasManageSettingsPermission()">
            ...
            </div>
        </div>
    </div>
    ...  
</form>  

Login with Volunteer Management System (VMS) Account

  • Revised Files:
    ./platform-client/app/common/auth/authentication.service.js
  • Explanation:
    This feature allows users to use their VMS account to login Ushahidi. There are two things we would like to verify. First, check whether the account and password are belong to VMS database. Second, check whether the user of the account have joined the appointed project in VMS.
$http.post(Util.url('/oauth/token'), payload).then(checkProjectMembership, handleRequestError);
checkProjectMembership = function() {
    var credential = {
        "email": username.toString(), 
        "password": password.toString() 
    };
    var Req = {
        method: 'POST', 
        url: 'https://vms-dev.herokuapp.com/api/auth', 
        headers: {
            'Content-Type': 'application/json', 
            'X-VMS-API-Key': '581dba93a4dbafa42a682d36b015d8484622f8e3543623bec5a291f67f5ddff1'
        }, 
        data: JSON.stringify(credential)
    };
    $http(Req).then(
        function(response){
            var vmshead = response.headers();
            var cpmReq = {
                method: 'GET', 
                url: 'https://vms-dev.herokuapp.com/api/attending_projects', 
                headers: {
                    'Content-Type': 'application/json', 
                    'X-VMS-API-Key': '581dba93a4dbafa42a682d36b015d8484622f8e3543623bec5a291f67f5ddff1',
                    'Authorization': vmshead.authorization
                }
            };
            var checkproj = false;
            $http(cpmReq).then(
                function(response){
                    var vmsproj = response.data;
                    for (var i = vmsproj.data.length - 1; i >= 0; i--) {
                        if (vmsproj.data[i].id == 72 || vmsproj.data[i].id == 22) {
                            checkproj = true;
                            break;
                        } 
                    }
                    if (checkproj==false) {
                        Notify.notify("Sorry, you haven't joined this project. Please join this project and login again.");
                        handleRequestError();
                    } else {
                        $http.post(Util.url('/oauth/token'), payload).then(handleRequestSuccess, handleRequestError);
                    }
                }, handleRequestError);
            }, handleRequestError);
};