Commit 6c43d39c7ccec7028709ff36197cd564c8dc0fb0
Exists in
master
and in
7 other branches
Merge branch 'feature-proposal-vote'
Showing
15 changed files
with
283 additions
and
136 deletions
Show diff stats
src/app/components/article-service/article.service.js
| ... | ... | @@ -162,20 +162,15 @@ |
| 162 | 162 | } |
| 163 | 163 | } |
| 164 | 164 | |
| 165 | - function voteProposal (proposal_id, params, cbSuccess, cbError){ | |
| 165 | + function voteProposal (proposal_id, params){ | |
| 166 | 166 | var url = service.apiArticles + proposal_id + '/vote'; |
| 167 | 167 | var paramsExtended = angular.extend({ |
| 168 | - private_token: $rootScope.currentUser.private_token | |
| 169 | - // private_token: 'e2198fdbcc20409f082829b4b5c0848e' | |
| 168 | + private_token: $rootScope.temporaryToken | |
| 170 | 169 | }, params); |
| 171 | 170 | |
| 172 | 171 | var encodedParams = angular.element.param(paramsExtended); |
| 173 | 172 | |
| 174 | - UtilService.post(url, encodedParams).then(function(response){ | |
| 175 | - cbSuccess(response); | |
| 176 | - }).catch(function(error){ | |
| 177 | - cbError(error); | |
| 178 | - }); | |
| 173 | + return UtilService.post(url, encodedParams); | |
| 179 | 174 | } |
| 180 | 175 | |
| 181 | 176 | function getEvents (community_id, params) { | ... | ... |
src/app/components/auth/auth.service.js
| ... | ... | @@ -53,11 +53,7 @@ |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | 55 | function activate (code) { |
| 56 | - var url = PATH.host +'/api/v1/activate'; | |
| 57 | - // var data = { | |
| 58 | - // private_token: API.token, | |
| 59 | - // activation_code: code | |
| 60 | - // }; | |
| 56 | + var url = PATH.host + '/api/v1/activate'; | |
| 61 | 57 | var encodedData = 'private_token=' + API.token; |
| 62 | 58 | encodedData += '&activation_code=' + code; |
| 63 | 59 | |
| ... | ... | @@ -77,12 +73,7 @@ |
| 77 | 73 | } |
| 78 | 74 | |
| 79 | 75 | function changePassword (code, newPassword, newPasswordConfirmation){ |
| 80 | - var url = PATH.host +'/api/v1/new_password'; | |
| 81 | - // var data = { | |
| 82 | - // code: code, | |
| 83 | - // password: newPassword, | |
| 84 | - // password_confirmation: newPasswordConfirmation | |
| 85 | - // }; | |
| 76 | + var url = PATH.host + '/api/v1/new_password'; | |
| 86 | 77 | var encodedData = 'code=' + code; |
| 87 | 78 | encodedData += '&password=' + newPassword; |
| 88 | 79 | encodedData += '&password_confirmation=' + newPasswordConfirmation; |
| ... | ... | @@ -103,7 +94,7 @@ |
| 103 | 94 | } |
| 104 | 95 | |
| 105 | 96 | function forgotPassword (data){ |
| 106 | - var url = PATH.host +'/api/v1/forgot_password'; | |
| 97 | + var url = PATH.host + '/api/v1/forgot_password'; | |
| 107 | 98 | var encodedData = ([ |
| 108 | 99 | 'value=' + data.login, |
| 109 | 100 | 'captcha_text=' + data.captcha_text, |
| ... | ... | @@ -145,9 +136,28 @@ |
| 145 | 136 | }, function(response) { |
| 146 | 137 | $log.debug('AuthService.login [FAIL] response', response); |
| 147 | 138 | $rootScope.$broadcast(AUTH_EVENTS.loginFailed); |
| 139 | + | |
| 140 | + return $q.reject(response); | |
| 148 | 141 | }); |
| 149 | 142 | } |
| 150 | 143 | |
| 144 | + function loginCaptcha (data) { | |
| 145 | + var url = PATH.host + '/api/v1/login-captcha'; | |
| 146 | + var encodedData = angular.element.param(data); | |
| 147 | + | |
| 148 | + return $http.post(url, encodedData).then(function(response){ | |
| 149 | + // SUCCESS | |
| 150 | + $log.debug('AuthService.loginCaptcha [SUCCESS] response', response); | |
| 151 | + | |
| 152 | + var temporaryToken = response.data.private_token; | |
| 153 | + Session.setTemporaryToken(temporaryToken); | |
| 154 | + $rootScope.temporaryToken = temporaryToken; | |
| 155 | + return temporaryToken; | |
| 156 | + }, function(response){ | |
| 157 | + return $q.reject(response.data); | |
| 158 | + }); | |
| 159 | + } | |
| 160 | + | |
| 151 | 161 | function logout () { |
| 152 | 162 | |
| 153 | 163 | Session.destroy(); |
| ... | ... | @@ -167,28 +177,13 @@ |
| 167 | 177 | return (service.isAuthenticated() && authorizedRoles.indexOf(Session.userRole) !== -1); |
| 168 | 178 | } |
| 169 | 179 | |
| 170 | - // function _encodeObj(obj){ | |
| 171 | - // var result = []; | |
| 172 | - // var str = null; | |
| 173 | - // var p = null; | |
| 174 | - | |
| 175 | - // for (p in obj) { | |
| 176 | - // if (obj.hasOwnProperty(p)) { | |
| 177 | - // // str = encodeURIComponent(p) + '=' + obj[p]; | |
| 178 | - // str = p + '=' + obj[p]; | |
| 179 | - // result.push(str); | |
| 180 | - // } | |
| 181 | - // } | |
| 182 | - | |
| 183 | - // return result.join('&'); | |
| 184 | - // } | |
| 185 | - | |
| 186 | 180 | var service = { |
| 187 | 181 | register: register, |
| 188 | 182 | activate: activate, |
| 189 | 183 | changePassword: changePassword, |
| 190 | 184 | forgotPassword: forgotPassword, |
| 191 | 185 | login: login, |
| 186 | + loginCaptcha: loginCaptcha, | |
| 192 | 187 | logout: logout, |
| 193 | 188 | isAuthenticated: isAuthenticated, |
| 194 | 189 | isAuthorized: isAuthorized |
| ... | ... | @@ -207,7 +202,7 @@ |
| 207 | 202 | |
| 208 | 203 | service.create = function(data) { |
| 209 | 204 | |
| 210 | - $localStorage.currentUser = data; | |
| 205 | + $localStorage.currentUser = data.user; | |
| 211 | 206 | $log.debug('User session created.', $localStorage.currentUser); |
| 212 | 207 | |
| 213 | 208 | return $localStorage.currentUser; |
| ... | ... | @@ -224,6 +219,14 @@ |
| 224 | 219 | return $localStorage.currentUser; |
| 225 | 220 | }; |
| 226 | 221 | |
| 222 | + service.setTemporaryToken = function (private_token) { | |
| 223 | + $localStorage.temporaryToken = private_token; | |
| 224 | + }; | |
| 225 | + | |
| 226 | + service.getTemporaryToken = function () { | |
| 227 | + return $localStorage.temporaryToken; | |
| 228 | + }; | |
| 229 | + | |
| 227 | 230 | return service; |
| 228 | 231 | } |
| 229 | 232 | ... | ... |
src/app/components/proposal-box/proposal-box.directive.js
| ... | ... | @@ -9,30 +9,34 @@ |
| 9 | 9 | function proposalBox() { |
| 10 | 10 | |
| 11 | 11 | /** @ngInject */ |
| 12 | - function ProposalBoxController($scope, $rootScope, $state, VOTE_STATUS, VOTE_OPTIONS, $log) { | |
| 12 | + function ProposalBoxController($scope, $rootScope, $state, $timeout, $interval, $window, VOTE_STATUS, VOTE_OPTIONS, AuthService, DialogaService, $log) { | |
| 13 | 13 | $log.debug('ProposalBoxController'); |
| 14 | 14 | |
| 15 | 15 | var vm = this; |
| 16 | 16 | vm.$scope = $scope; |
| 17 | 17 | vm.$rootScope = $rootScope; |
| 18 | 18 | vm.$state = $state; |
| 19 | + vm.$timeout = $timeout; | |
| 20 | + vm.$interval = $interval; | |
| 21 | + vm.$window = $window; | |
| 19 | 22 | vm.VOTE_STATUS = VOTE_STATUS; |
| 20 | 23 | vm.VOTE_OPTIONS = VOTE_OPTIONS; |
| 24 | + vm.AuthService = AuthService; | |
| 21 | 25 | vm.$log = $log; |
| 22 | 26 | |
| 23 | 27 | vm.init(); |
| 24 | 28 | vm.addListeners(); |
| 25 | 29 | } |
| 26 | 30 | |
| 27 | - ProposalBoxController.prototype.init = function () { | |
| 31 | + ProposalBoxController.prototype.init = function() { | |
| 28 | 32 | |
| 29 | 33 | var vm = this; |
| 30 | 34 | |
| 31 | - vm.canVote = vm.canVote || false; | |
| 35 | + vm.showVote = vm.showVote || false; | |
| 32 | 36 | vm.focus = vm.focus || false; |
| 33 | 37 | vm.STATE = null; |
| 34 | 38 | vm.errorOnSkip = false; |
| 35 | - vm.showAuthMessage = null; | |
| 39 | + vm.showCaptchaForm = null; | |
| 36 | 40 | vm.voteProposalRedirectURI = null; |
| 37 | 41 | |
| 38 | 42 | var slug = vm.topic.slug; |
| ... | ... | @@ -40,37 +44,52 @@ |
| 40 | 44 | vm.voteProposalRedirectURI = 'state=programa&task=vote-proposal&slug=' + slug + '&proposal_id=' + proposal_id; |
| 41 | 45 | }; |
| 42 | 46 | |
| 43 | - ProposalBoxController.prototype.addListeners = function () { | |
| 47 | + ProposalBoxController.prototype.addListeners = function() { | |
| 44 | 48 | var vm = this; |
| 45 | 49 | |
| 46 | - vm.$scope.$on('proposal-box:proposal-loaded', function(event, data){ | |
| 47 | - if(data.success){ | |
| 50 | + vm.$scope.$on('proposal-box:proposal-loaded', function(event, data) { | |
| 51 | + if (data.success) { | |
| 48 | 52 | vm.STATE = null; |
| 49 | 53 | } |
| 50 | 54 | |
| 51 | - if(data.error){ | |
| 55 | + if (data.error) { | |
| 52 | 56 | vm.errorOnSkip = data.error; |
| 53 | 57 | } |
| 54 | 58 | }); |
| 55 | 59 | |
| 56 | - vm.$scope.$on('proposal-box:vote-response', function(event, data){ | |
| 57 | - vm.$log.debug('proposal-box:vote-response'); | |
| 58 | - vm.$log.debug('event', event); | |
| 59 | - vm.$log.debug('data', data); | |
| 60 | - | |
| 61 | - if(data.success) { | |
| 60 | + vm.$scope.$on('proposal-box:vote-response', function(event, data) { | |
| 61 | + if (data.success) { | |
| 62 | 62 | vm.STATE = vm.VOTE_STATUS.SUCCESS; |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | - if(data.error) { | |
| 65 | + if (data.error) { | |
| 66 | 66 | vm.STATE = vm.VOTE_STATUS.ERROR; |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | - vm.message = data.message; | |
| 69 | + if (data.code === 401) { | |
| 70 | + vm.message = 'Não autorizado.'; | |
| 71 | + } | |
| 72 | + | |
| 73 | + vm.messageCode = data.code; | |
| 70 | 74 | }); |
| 75 | + | |
| 76 | + // Load captcha | |
| 77 | + var stop = null; | |
| 78 | + stop = vm.$interval(function() { | |
| 79 | + var $el = angular.element('#serpro_captcha'); | |
| 80 | + | |
| 81 | + if ($el && $el.length > 0) { | |
| 82 | + vm.$window.initCaptcha($el[0]); | |
| 83 | + vm.$interval.cancel(stop); | |
| 84 | + stop = undefined; | |
| 85 | + }else { | |
| 86 | + vm.$log.debug('captcha element not found.'); | |
| 87 | + } | |
| 88 | + | |
| 89 | + }, 10); | |
| 71 | 90 | }; |
| 72 | 91 | |
| 73 | - ProposalBoxController.prototype.showContent = function (slug) { | |
| 92 | + ProposalBoxController.prototype.showContent = function(slug) { | |
| 74 | 93 | var vm = this; |
| 75 | 94 | |
| 76 | 95 | vm.$state.go('programa', { |
| ... | ... | @@ -81,45 +100,106 @@ |
| 81 | 100 | }); |
| 82 | 101 | }; |
| 83 | 102 | |
| 84 | - ProposalBoxController.prototype.vote = function (value) { | |
| 103 | + ProposalBoxController.prototype.canVote = function() { | |
| 85 | 104 | var vm = this; |
| 86 | 105 | |
| 87 | - if(vm.$rootScope.currentUser){ | |
| 88 | - vm.$scope.$emit('proposal-box:vote', { | |
| 89 | - OPTION: value, | |
| 90 | - proposal_id: vm.proposal.id | |
| 91 | - }); | |
| 92 | - vm.$log.debug('Sending vote', value); | |
| 93 | - }else{ | |
| 94 | - vm.$log.info('Must be logged in...'); | |
| 95 | - vm.showAuthMessage = true; | |
| 96 | - } | |
| 106 | + return !!vm.$rootScope.temporaryToken; | |
| 97 | 107 | }; |
| 98 | 108 | |
| 99 | - ProposalBoxController.prototype.voteDown = function () { | |
| 109 | + ProposalBoxController.prototype.submitCaptcha = function($event, captchaForm) { | |
| 100 | 110 | var vm = this; |
| 101 | 111 | |
| 102 | - vm.STATE = vm.VOTE_STATUS.LOADING; | |
| 103 | - vm.$scope.$emit('proposal-box:vote', { | |
| 104 | - OPTION: vm.VOTE_OPTIONS.DOWN, | |
| 105 | - proposal_id: vm.proposal.id | |
| 112 | + var target = $event.target; | |
| 113 | + var $target = angular.element(target); | |
| 114 | + var $captcha = $target.find('[name="txtToken_captcha_serpro_gov_br"]'); | |
| 115 | + | |
| 116 | + vm.sendingCaptcha = true; | |
| 117 | + vm.AuthService.loginCaptcha({ | |
| 118 | + captcha_text: captchaForm.captcha_text.$modelValue, | |
| 119 | + txtToken_captcha_serpro_gov_br: $captcha.val() | |
| 120 | + }).then(function(data) { | |
| 121 | + // SUCCESS | |
| 122 | + vm.$log.debug('register success.data', data); | |
| 123 | + | |
| 124 | + // SEND VOTE | |
| 125 | + if (vm._oldVoteValue) { | |
| 126 | + vm.vote(vm._oldVoteValue); | |
| 127 | + vm._oldVoteValue = null; | |
| 128 | + } | |
| 129 | + // hide captcha form | |
| 130 | + vm.showCaptchaForm = false; | |
| 131 | + | |
| 132 | + }, function(data) { | |
| 133 | + // ERROR | |
| 134 | + vm.$log.debug('register error.data', data); | |
| 135 | + | |
| 136 | + vm.sendingCaptchaError = { | |
| 137 | + code: data.status, | |
| 138 | + message: data.message || ('Erro (' + data.status + '). Já estamos trabalhando para resolver o problema.<br/>Por favor, tente novamente mais tarde') | |
| 139 | + }; | |
| 140 | + | |
| 141 | + if (angular.equals(vm.sendingCaptchaError.message, 'Internal captcha validation error')) { | |
| 142 | + vm.sendingCaptchaError.message = 'Erro interno ao tentar validar captcha.<br/><br/>Já estamos trabalhando para resolver o problema.<br/>Por favor, tente novamente mais tarde.'; | |
| 143 | + } | |
| 144 | + | |
| 145 | + }, function(data) { | |
| 146 | + // UPDATE | |
| 147 | + vm.$log.debug('register update.data', data); | |
| 148 | + }).finally(function() { | |
| 149 | + vm.sendingCaptcha = false; | |
| 106 | 150 | }); |
| 107 | - vm.$log.debug('Sending vote'); | |
| 108 | 151 | }; |
| 109 | 152 | |
| 110 | - ProposalBoxController.prototype.skip = function () { | |
| 153 | + ProposalBoxController.prototype.captchaTryAgain = function() { | |
| 154 | + var vm = this; | |
| 155 | + | |
| 156 | + vm.showCaptchaForm = true; | |
| 157 | + vm.sendingCaptcha = false; | |
| 158 | + vm.sendingCaptchaError = false; | |
| 159 | + vm.message = null; | |
| 160 | + | |
| 161 | + // reload new captcha | |
| 162 | + var $el = angular.element('#serpro_captcha'); | |
| 163 | + vm.$window.reloadCaptcha($el[0]); | |
| 164 | + | |
| 165 | + // focus on input | |
| 166 | + angular.element('#captcha_text').val('').focus(); | |
| 167 | + }; | |
| 168 | + | |
| 169 | + ProposalBoxController.prototype.vote = function(value) { | |
| 170 | + var vm = this; | |
| 171 | + | |
| 172 | + vm._oldVoteValue = value; | |
| 173 | + if (vm.canVote()) { | |
| 174 | + if (vm.doVote) { | |
| 175 | + vm.doVote({ | |
| 176 | + proposal_id: vm.proposal.id, | |
| 177 | + value: value | |
| 178 | + }); | |
| 179 | + }else { | |
| 180 | + vm.$log.error('No vote function to handler votes'); | |
| 181 | + } | |
| 182 | + }else { | |
| 183 | + vm.$log.debug('You cannot vote.'); | |
| 184 | + vm.showCaptchaForm = true; | |
| 185 | + | |
| 186 | + angular.element('#captcha_text').focus(); | |
| 187 | + } | |
| 188 | + }; | |
| 189 | + | |
| 190 | + ProposalBoxController.prototype.skip = function() { | |
| 111 | 191 | var vm = this; |
| 112 | 192 | |
| 113 | 193 | vm.errorOnSkip = false; |
| 114 | 194 | vm.STATE = vm.VOTE_STATUS.LOADING; |
| 115 | - vm.$scope.$emit('proposal-box:vote', { | |
| 116 | - OPTION: vm.VOTE_OPTIONS.SKIP, | |
| 117 | - proposal_id: vm.proposal.id | |
| 195 | + vm.doVote({ | |
| 196 | + proposal_id: vm.proposal.id, | |
| 197 | + value: vm.VOTE_OPTIONS.SKIP | |
| 118 | 198 | }); |
| 119 | 199 | vm.$log.debug('Sending vote'); |
| 120 | 200 | }; |
| 121 | 201 | |
| 122 | - ProposalBoxController.prototype.getSocialUrl = function () { | |
| 202 | + ProposalBoxController.prototype.getSocialUrl = function() { | |
| 123 | 203 | var vm = this; |
| 124 | 204 | |
| 125 | 205 | return vm.$state.href('programa', { |
| ... | ... | @@ -135,8 +215,9 @@ |
| 135 | 215 | proposal: '=', |
| 136 | 216 | topic: '=', |
| 137 | 217 | category: '=', |
| 138 | - canVote: '=', | |
| 139 | - focus: '@' | |
| 218 | + showVote: '=', | |
| 219 | + focus: '@', | |
| 220 | + doVote: '&' | |
| 140 | 221 | // @ -> Text binding / one-way binding |
| 141 | 222 | // = -> Direct model binding / two-way binding |
| 142 | 223 | // & -> Behaviour binding / Method binding | ... | ... |
src/app/components/proposal-box/proposal-box.html
| ... | ... | @@ -52,8 +52,10 @@ |
| 52 | 52 | </div> |
| 53 | 53 | <div class="feedback" ng-if="vm.STATE === vm.VOTE_STATUS.ERROR"> |
| 54 | 54 | <p class="feedback--title">Erro!</p> |
| 55 | - <p class="feedback--message" ng-if="vm.message"> | |
| 56 | - Motivo: {{vm.message}} | |
| 55 | + <p class="feedback--message" ng-if="vm.messageCode === 401"> | |
| 56 | + Não autorizado. Insira um novo captcha. | |
| 57 | + <br> | |
| 58 | + <button type="button" class="btn btn-link" ng-click="vm.captchaTryAgain()">Gerar novo captcha</button> | |
| 57 | 59 | </p> |
| 58 | 60 | </div> |
| 59 | 61 | </div> |
| ... | ... | @@ -65,18 +67,48 @@ |
| 65 | 67 | </div> |
| 66 | 68 | </div> |
| 67 | 69 | </div> |
| 68 | - <div ng-show="vm.showAuthMessage"> | |
| 70 | + <div ng-show="vm.showCaptchaForm"> | |
| 69 | 71 | <div class="proposal-message-panel"> |
| 70 | 72 | <div class="row"> |
| 71 | 73 | <div class="row-height"> |
| 72 | 74 | <div class="col-sm-12 col-height col-middle"> |
| 73 | 75 | <div class="inside inside-full-height"> |
| 74 | 76 | <div class="content text-center"> |
| 75 | - <p>Você precisa estar logado para votar na proposta</p> | |
| 76 | - <br> | |
| 77 | - <p> | |
| 78 | - <a ui-sref="entrar({redirect_uri: vm.voteProposalRedirectURI})">Clique aqui para ir para a página de login</a> | |
| 79 | - </p> | |
| 77 | + <div ng-show="vm.sendingCaptcha"> | |
| 78 | + <p>Enviando captcha...</p> | |
| 79 | + </div> | |
| 80 | + <div ng-hide="vm.sendingCaptcha"> | |
| 81 | + <div class="row feedback-message" ng-show="vm.sendingCaptchaError"> | |
| 82 | + <div class="col-sm-12"> | |
| 83 | + <div class="feedback--title alert alert-danger">Erro!</div> | |
| 84 | + <div class="feedback--message" ng-if="!vm.message"> | |
| 85 | + <p ng-bind-html="vm.sendingCaptchaError.message"></p> | |
| 86 | + </div> | |
| 87 | + <div> | |
| 88 | + <button type="reset" class="btn btn-link" ng-click="vm.captchaTryAgain()">Tentar novamente</button> | |
| 89 | + <button type="reset" class="btn btn-link" ng-click="vm.showCaptchaForm = false">Voltar</button> | |
| 90 | + </div> | |
| 91 | + </div> | |
| 92 | + </div> | |
| 93 | + <div ng-hide="vm.sendingCaptchaError"> | |
| 94 | + <form name="captchaForm" ng-submit="vm.submitCaptcha($event, captchaForm)"> | |
| 95 | + <div class="form-group"> | |
| 96 | + <div id="serpro_captcha" class="captcha"></div> | |
| 97 | + <div class="captcha">Digite os caracteres acima:</div> | |
| 98 | + <div class="captcha"> | |
| 99 | + <input type="text" name="captcha_text" id="captcha_text" aria-label="Escreva os caracteres do captcha aqui" ng-model="vm._captcha_text" ng-minlength="" ng-maxlength="" required> | |
| 100 | + <validation-messages field="captchaForm.captcha_text"></validation-messages> | |
| 101 | + </div> | |
| 102 | + </div> | |
| 103 | + <div class="form-group"> | |
| 104 | + <button type="submit" class="btn btn-lg btn-block btn-submit">Enviar</button> | |
| 105 | + </div> | |
| 106 | + <div class="form-group"> | |
| 107 | + <button type="reset" class="btn btn-link" ng-click="vm.showCaptchaForm = false">Voltar</button> | |
| 108 | + </div> | |
| 109 | + </form> | |
| 110 | + </div> | |
| 111 | + </div> | |
| 80 | 112 | </div> |
| 81 | 113 | </div> |
| 82 | 114 | </div> |
| ... | ... | @@ -112,12 +144,12 @@ |
| 112 | 144 | <div class="proposal-box--content"> |
| 113 | 145 | <div class="proposal-box--content-inner">{{vm.proposal.abstract}}</div> |
| 114 | 146 | </div> |
| 115 | - <div ng-hide="vm.canVote" class="proposal-box--join"> | |
| 147 | + <div ng-hide="vm.showVote" class="proposal-box--join"> | |
| 116 | 148 | <button class="btn btn-link color-theme-common-fg" ng-click="vm.showContent(vm.topic.slug)"> |
| 117 | 149 | Participe |
| 118 | 150 | </button> |
| 119 | 151 | </div> |
| 120 | - <div ng-show="vm.canVote" class="proposal-box--actions text-center"> | |
| 152 | + <div ng-show="vm.showVote" class="proposal-box--actions text-center"> | |
| 121 | 153 | <div class="row"> |
| 122 | 154 | <div class="col-xs-4"> |
| 123 | 155 | <div class="action vote_for" ng-click="vm.vote(vm.VOTE_OPTIONS.UP)"> | ... | ... |
src/app/components/proposal-box/proposal-box.scss
| ... | ... | @@ -91,9 +91,15 @@ |
| 91 | 91 | .content { |
| 92 | 92 | color: #262626; |
| 93 | 93 | font-size: 24px; |
| 94 | + font-size: 2.4rem; | |
| 94 | 95 | font-weight: bold; |
| 95 | 96 | line-height: 24px; |
| 96 | 97 | padding: 10px 30px; |
| 98 | + | |
| 99 | + form { | |
| 100 | + font-size: 18px; | |
| 101 | + font-size: 1.8rem; | |
| 102 | + } | |
| 97 | 103 | } |
| 98 | 104 | |
| 99 | 105 | .message-icon { |
| ... | ... | @@ -108,11 +114,13 @@ |
| 108 | 114 | |
| 109 | 115 | &--title { |
| 110 | 116 | font-size: 22px; |
| 117 | + font-size: 2.2rem; | |
| 111 | 118 | font-weight: bold; |
| 112 | 119 | } |
| 113 | 120 | |
| 114 | 121 | &--message { |
| 115 | 122 | font-size: 14px; |
| 123 | + font-size: 1.4rem; | |
| 116 | 124 | font-weight: normal; |
| 117 | 125 | line-height: 20px; |
| 118 | 126 | margin-top: 48px; | ... | ... |
src/app/components/proposal-grid/proposal-grid.html
| 1 | 1 | <div class="proposal-grid row"> |
| 2 | 2 | <div ng-repeat="proposal in vm.proposals as results"> |
| 3 | - <proposal-box proposal="proposal" topic="proposal.parent" category="proposal.parent.categories[0]" class="col-xs-12 col-sm-6"></proposal-box> | |
| 3 | + <proposal-box proposal="proposal" topic="proposal.parent" category="proposal.parent.categories[0]" show-vote="false" class="col-xs-12 col-sm-6"></proposal-box> | |
| 4 | 4 | <div ng-if="$odd" class="clearfix"></div> |
| 5 | 5 | </div> |
| 6 | 6 | <div class="animate-repeat" ng-if="results.length == 0"> | ... | ... |
src/app/components/proposal-list/proposal-list.directive.js
src/app/index.run.js
src/app/layout.scss
| ... | ... | @@ -9,7 +9,6 @@ |
| 9 | 9 | display: table-cell; |
| 10 | 10 | float: none; |
| 11 | 11 | height: 100%; |
| 12 | - background-color: #181e21; | |
| 13 | 12 | } |
| 14 | 13 | |
| 15 | 14 | .col-top { |
| ... | ... | @@ -206,6 +205,13 @@ |
| 206 | 205 | margin-left: 10px; |
| 207 | 206 | padding: 0; |
| 208 | 207 | border-radius: 100%; |
| 208 | + | |
| 209 | + &:hover, | |
| 210 | + &:focus, | |
| 211 | + &:active { | |
| 212 | + color: #fff; | |
| 213 | + border-color: #fff; | |
| 214 | + } | |
| 209 | 215 | } |
| 210 | 216 | |
| 211 | 217 | ul.list-color { |
| ... | ... | @@ -224,7 +230,7 @@ ul.list-color li:before { |
| 224 | 230 | } |
| 225 | 231 | |
| 226 | 232 | ul.list-color li:before { |
| 227 | - content: "• "; | |
| 233 | + content: "\2022"; | |
| 228 | 234 | font-weight: bold; |
| 229 | 235 | font-size: 20px; |
| 230 | 236 | position: relative; |
| ... | ... | @@ -333,7 +339,7 @@ blockquote { |
| 333 | 339 | position: relative; |
| 334 | 340 | margin: 0px; |
| 335 | 341 | border-left: none; |
| 336 | - // line-height: 28px; | |
| 342 | + | |
| 337 | 343 | &:before { |
| 338 | 344 | content: "\231C"; |
| 339 | 345 | font-size: 300px; | ... | ... |
src/app/pages/programas/programa.controller.js
| ... | ... | @@ -82,7 +82,10 @@ |
| 82 | 82 | } |
| 83 | 83 | |
| 84 | 84 | vm.loadingTopProposals = true; |
| 85 | - vm.DialogaService.getProposalsByTopicId(vm.article.id, {}, function(data) { | |
| 85 | + vm.DialogaService.getProposalsByTopicId(vm.article.id, { | |
| 86 | + 'limit': 5 | |
| 87 | + }, function(data) { | |
| 88 | + vm.total_proposals = parseInt(data._obj.headers('total')); | |
| 86 | 89 | vm.proposals = data.articles; |
| 87 | 90 | vm.proposalsTopFive = vm.proposals.slice(0, 5); |
| 88 | 91 | vm.proposalsTopRated = vm.proposals.slice(0, 3); |
| ... | ... | @@ -142,24 +145,6 @@ |
| 142 | 145 | vm.proposalStatus = vm.PROPOSAL_STATUS.ERROR; |
| 143 | 146 | }); |
| 144 | 147 | }); |
| 145 | - | |
| 146 | - vm.$scope.$on('proposal-box:vote', function(event, params) { | |
| 147 | - // vm.$log.debug('event', event); | |
| 148 | - // vm.$log.debug('params', params); | |
| 149 | - var proposal_id = params.proposal_id; | |
| 150 | - var OPTION = params.OPTION; | |
| 151 | - | |
| 152 | - switch (OPTION){ | |
| 153 | - case vm.VOTE_OPTIONS.UP: | |
| 154 | - case vm.VOTE_OPTIONS.DOWN: | |
| 155 | - case vm.VOTE_OPTIONS.SKIP: | |
| 156 | - vm.vote(proposal_id, OPTION); | |
| 157 | - break; | |
| 158 | - default: | |
| 159 | - vm.$log.error('Vote option not handled:', OPTION); | |
| 160 | - break; | |
| 161 | - } | |
| 162 | - }); | |
| 163 | 148 | }; |
| 164 | 149 | |
| 165 | 150 | ProgramaPageController.prototype.loadProposalById = function(proposal_id) { |
| ... | ... | @@ -219,31 +204,28 @@ |
| 219 | 204 | return; |
| 220 | 205 | } |
| 221 | 206 | |
| 222 | - if (!vm.$rootScope.currentUser) { | |
| 223 | - // vm.$state.go('entrar', { | |
| 224 | - // redirect_uri: vm.sendProposalRedirectURI, | |
| 225 | - // message: 'Você precisa estar logado para votar em uma proposta.' | |
| 226 | - // }, { | |
| 227 | - // location: true | |
| 228 | - // }); | |
| 207 | + if (!vm.$rootScope.temporaryToken) { | |
| 208 | + vm.$log.debug('"temporaryToken" not defined. Abort.'); | |
| 229 | 209 | return; |
| 230 | 210 | } |
| 231 | 211 | |
| 232 | 212 | vm.DialogaService.voteProposal(proposal_id, { |
| 233 | 213 | value: value |
| 234 | - }, function(response) { | |
| 235 | - vm.$log.debug('response', response); | |
| 214 | + }).then(function(response) { | |
| 215 | + vm.$log.debug('voteProposal response', response); | |
| 236 | 216 | |
| 237 | 217 | response.success = true; |
| 238 | 218 | vm.$scope.$broadcast('proposal-box:vote-response', response); |
| 239 | - }, function(error) { | |
| 240 | - vm.$log.error('error', error); | |
| 219 | + }, function(response) { | |
| 220 | + vm.$log.debug('voteProposal error', response); | |
| 221 | + | |
| 222 | + response.error = true; | |
| 223 | + vm.$scope.$broadcast('proposal-box:vote-response', response); | |
| 224 | + }).finally(function(response){ | |
| 225 | + vm.$log.debug('voteProposal finally', response); | |
| 241 | 226 | |
| 242 | - error.error = true; | |
| 243 | - vm.$scope.$broadcast('proposal-box:vote-response', error); | |
| 244 | 227 | }); |
| 245 | 228 | }; |
| 246 | - ProgramaPageController.prototype.voteHasBeenComputed = function() {}; | |
| 247 | 229 | |
| 248 | 230 | ProgramaPageController.prototype.showProposalsList = function() { |
| 249 | 231 | var vm = this; | ... | ... |
src/app/pages/programas/programa.html
| ... | ... | @@ -90,7 +90,14 @@ |
| 90 | 90 | <div> |
| 91 | 91 | <div class="col-xs-12" ng-if="!pagePrograma.loadingProposalBox && pagePrograma.randomProposal" ng-class="{'focused-proposal': !!pagePrograma.search.proposal_id}"> |
| 92 | 92 | <h3 class="color-theme-fg">Apoie outras propostas</h3> |
| 93 | - <proposal-box proposal="pagePrograma.randomProposal" topic="pagePrograma.article" category="pagePrograma.category" can-vote="true" focus="{{pagePrograma.search.proposal_id}}" ></proposal-box> | |
| 93 | + <proposal-box | |
| 94 | + proposal="pagePrograma.randomProposal" | |
| 95 | + topic="pagePrograma.article" | |
| 96 | + category="pagePrograma.category" | |
| 97 | + show-vote="true" | |
| 98 | + focus="{{pagePrograma.search.proposal_id}}" | |
| 99 | + do-vote="pagePrograma.vote(proposal_id, value)" | |
| 100 | + ></proposal-box> | |
| 94 | 101 | </div> |
| 95 | 102 | |
| 96 | 103 | <!-- Loading Proposal Box --> |
| ... | ... | @@ -133,7 +140,7 @@ |
| 133 | 140 | <div class="row"> |
| 134 | 141 | <div class="col-xs-12"> |
| 135 | 142 | <a ui-sref="ranking({tema: pagePrograma.category.slug, programa: pagePrograma.article.slug})" class="btn btn-link"> |
| 136 | - <span ng-if="pagePrograma.proposals.length > 1">Veja todas as {{pagePrograma.proposals.length}} propostas</span> | |
| 143 | + <span ng-if="pagePrograma.proposals.length > 1">Veja todas as {{pagePrograma.total_proposals}} propostas</span> | |
| 137 | 144 | <span ng-if="pagePrograma.proposals.length === 1">Ir para a página de ranking</span> |
| 138 | 145 | </a> |
| 139 | 146 | </div> | ... | ... |
src/app/pages/programas/programas.controller.js
| ... | ... | @@ -139,6 +139,21 @@ |
| 139 | 139 | |
| 140 | 140 | }; |
| 141 | 141 | |
| 142 | + ProgramasPageController.prototype.submitSearch = function() { | |
| 143 | + var vm = this; | |
| 144 | + | |
| 145 | + vm.loadingFilter = true; | |
| 146 | + | |
| 147 | + // scroll to result grid | |
| 148 | + var $searchResult = angular.element('#search-result'); | |
| 149 | + if ($searchResult && $searchResult.length > 0) { | |
| 150 | + angular.element('body').animate({scrollTop: $searchResult.offset().top}, 'fast'); | |
| 151 | + vm.filtredPrograms = vm.getFiltredPrograms(); | |
| 152 | + }else { | |
| 153 | + vm.$log.warn('#search-result element not found.'); | |
| 154 | + } | |
| 155 | + }; | |
| 156 | + | |
| 142 | 157 | ProgramasPageController.prototype.showAllPrograms = function($event) { |
| 143 | 158 | var vm = this; |
| 144 | 159 | $event.stopPropagation(); | ... | ... |
src/app/pages/programas/programas.html
| ... | ... | @@ -26,7 +26,7 @@ |
| 26 | 26 | <label for="articleQueryFilter" class="control-label sr-only">Buscar programas:</label> |
| 27 | 27 | <input id="articleQueryFilter" type="search" class="form-control input-search" ng-model="pageProgramas.query" placeholder="Buscar programas" aria-label="Buscar programas" > |
| 28 | 28 | <span class="input-group-btn"> |
| 29 | - <button type="button" class="btn btn-default" ng-click="pageProgramas.search()"> | |
| 29 | + <button type="button" class="btn btn-default" ng-click="pageProgramas.submitSearch()"> | |
| 30 | 30 | <span class="icon-circle icon-small color-theme-common-bg"> |
| 31 | 31 | <span class="glyphicon glyphicon-search"></span> |
| 32 | 32 | </span> |
| ... | ... | @@ -58,7 +58,7 @@ |
| 58 | 58 | <label for="articleQueryFilter" class="control-label sr-only">Buscar programas:</label> |
| 59 | 59 | <input id="articleQueryFilter" type="search" class="form-control input-search" ng-model="pageProgramas.query" placeholder="Buscar programas" aria-label="Buscar programas" > |
| 60 | 60 | <span class="input-group-btn"> |
| 61 | - <button type="button" class="btn btn-default" ng-click="pageProgramas.search()"> | |
| 61 | + <button type="button" class="btn btn-default" ng-click="pageProgramas.submitSearch()"> | |
| 62 | 62 | <span class="icon-circle icon-small color-theme-common-bg"> |
| 63 | 63 | <span class="glyphicon glyphicon-search"></span> |
| 64 | 64 | </span> |
| ... | ... | @@ -68,7 +68,7 @@ |
| 68 | 68 | </div> |
| 69 | 69 | </div> |
| 70 | 70 | </div> |
| 71 | - <div class="row"> | |
| 71 | + <div id="search-result" class="row"> | |
| 72 | 72 | <div class="col-sm-12"> |
| 73 | 73 | <header class="header"> |
| 74 | 74 | <h2>Conheça os programas</h2> | ... | ... |
src/app/pages/propostas/propostas.controller.js
| ... | ... | @@ -6,11 +6,12 @@ |
| 6 | 6 | .controller('PropostasPageController', PropostasPageController); |
| 7 | 7 | |
| 8 | 8 | /** @ngInject */ |
| 9 | - function PropostasPageController(DialogaService, $scope, $location, $filter, $log) { | |
| 9 | + function PropostasPageController(DialogaService, $scope, $rootScope, $location, $filter, $log) { | |
| 10 | 10 | var vm = this; |
| 11 | 11 | |
| 12 | 12 | vm.DialogaService = DialogaService; |
| 13 | 13 | vm.$scope = $scope; |
| 14 | + vm.$rootScope = $rootScope; | |
| 14 | 15 | vm.$location = $location; |
| 15 | 16 | vm.$filter = $filter; |
| 16 | 17 | vm.$log = $log; |
| ... | ... | @@ -18,6 +19,7 @@ |
| 18 | 19 | vm.init(); |
| 19 | 20 | vm.loadData(); |
| 20 | 21 | // vm.attachListeners(); // attach listeners after load data (SYNC) |
| 22 | + vm.$rootScope.focusMainContent(); | |
| 21 | 23 | |
| 22 | 24 | $log.debug('PropostasPageController'); |
| 23 | 25 | } |
| ... | ... | @@ -156,4 +158,19 @@ |
| 156 | 158 | return output; |
| 157 | 159 | }; |
| 158 | 160 | |
| 161 | + PropostasPageController.prototype.submitSearch = function() { | |
| 162 | + var vm = this; | |
| 163 | + | |
| 164 | + vm.loadingFilter = true; | |
| 165 | + | |
| 166 | + // scroll to result grid | |
| 167 | + var $searchResult = angular.element('#search-result'); | |
| 168 | + if ($searchResult && $searchResult.length > 0) { | |
| 169 | + angular.element('body').animate({scrollTop: $searchResult.offset().top}, 'fast'); | |
| 170 | + vm.filtredProposals = vm.getFiltredProposals(); | |
| 171 | + }else { | |
| 172 | + vm.$log.warn('#search-result element not found.'); | |
| 173 | + } | |
| 174 | + }; | |
| 175 | + | |
| 159 | 176 | })(); | ... | ... |
src/app/pages/propostas/propostas.html
| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | </div> |
| 7 | 7 | </div> |
| 8 | 8 | |
| 9 | -<div class="page--propostas"> | |
| 9 | +<div class="page--propostas" role="main"> | |
| 10 | 10 | |
| 11 | 11 | <section class="section-info" ng-if="pagePropostas.loading || pagePropostas.error"> |
| 12 | 12 | <div class="container"> |
| ... | ... | @@ -46,7 +46,7 @@ |
| 46 | 46 | <label for="articleQueryFilter" class="control-label sr-only">Buscar propostas:</label> |
| 47 | 47 | <input id="articleQueryFilter" type="search" class="form-control input-search" ng-model="pagePropostas.query" placeholder="Buscar propostas" aria-label="Buscar propostas" > |
| 48 | 48 | <span class="input-group-btn"> |
| 49 | - <button type="button" class="btn btn-default" ng-click="pagePropostas.search()"> | |
| 49 | + <button type="button" class="btn btn-default" ng-click="pagePropostas.submitSearch()"> | |
| 50 | 50 | <span class="icon-circle icon-small color-theme-common-bg"> |
| 51 | 51 | <span class="glyphicon glyphicon-search"></span> |
| 52 | 52 | </span> |
| ... | ... | @@ -78,7 +78,7 @@ |
| 78 | 78 | <label for="articleQueryFilter" class="control-label sr-only">Buscar propostas:</label> |
| 79 | 79 | <input id="articleQueryFilter" type="search" class="form-control input-search" ng-model="pagePropostas.query" placeholder="Buscar propostas" aria-label="Buscar propostas" > |
| 80 | 80 | <span class="input-group-btn"> |
| 81 | - <button type="button" class="btn btn-default" ng-click="pagePropostas.search()"> | |
| 81 | + <button type="button" class="btn btn-default" ng-click="pagePropostas.submitSearch()"> | |
| 82 | 82 | <span class="icon-circle icon-small color-theme-common-bg"> |
| 83 | 83 | <span class="glyphicon glyphicon-search"></span> |
| 84 | 84 | </span> |
| ... | ... | @@ -89,7 +89,7 @@ |
| 89 | 89 | </div> |
| 90 | 90 | </div> |
| 91 | 91 | |
| 92 | - <div class="row" ng-if="pagePropostas.proposals"> | |
| 92 | + <div id="search-result" class="row" ng-if="pagePropostas.proposals"> | |
| 93 | 93 | <div class="col-sm-12"> |
| 94 | 94 | <header class="header"> |
| 95 | 95 | <h2>Total de Propostas: "<b>{{pagePropostas.filtredProposals.length}} propostas</b>"</h2> | ... | ... |