Skip to content
Open
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
9 changes: 9 additions & 0 deletions src/components/auth/auth.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,13 @@ export default class AuthService {
checkEmail(email) {
return this.$fetch.post('/v1/auth/checkEmail', { email });
}

/**
* Invalidated the API token.
*
* @return {promise}
*/
signOut() {
return this.$fetch.post('/v1/auth/logout');
}
}
64 changes: 53 additions & 11 deletions src/components/layout/top-navbar/top-navbar.controller.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,69 @@
export default class TopNavbarController {
/** @ngInject */
constructor($translate, $auth, $state, $toast) {
const languages = [
constructor($translate, $auth, $state, $toast, $mdDialog, AuthService) {
Object.assign(this, {
$translate, $auth, $state, $toast, $mdDialog, AuthService,
});

this.languages = [
{ key: 'EN', name: 'English' },
{ key: 'TW', name: '繁體中文' },
{ key: 'CN', name: '简体中文' },
];

const currentLanguage = $translate.use();

Object.assign(this, {
$translate, $auth, $state, $toast, languages, currentLanguage,
});
this.currentLanguage = $translate.use();
}

/**
* Change the language of UI.
*
* @param {string} key
* @return {void}
*/
changeLanguage(key) {
this.$translate.use(key);
this.currentLanguage = key;
}

signout() {
this.$auth.logout();
this.$state.go('auth.signin');
this.$toast.show('Sign Out Success!');
/**
* Do the sign out flow when user click the sign out button.
*
* @param {Object} $event
* @return {void}
*/
signOut($event) {
this.showConfirmMessage($event).then(this.executedSignOut);
}

/**
* Show a confirm message for sign out.
*
* @param {Object} $event
* @return {Promise}
*/
showConfirmMessage($event) {
const confirm = this.$mdDialog.confirm()
.title('Would you like to sign out without your upload?')
.textContent(`You have in progress opreations
or uploads and leaving now will cancel them.Still leaving?`)
.ariaLabel('Sign out')
.targetEvent($event)
.ok('Leave')
.cancel('Stay');

return this.$mdDialog.show(confirm);
}

/**
* Executed sign out when user confirm the message.
*
* @return {Promise} [description]
*/
executedSignOut = () => this.AuthService.signOut()
.then(() => {
this.$auth.logout();
this.$state.go('auth.signin');
this.$toast.show('Sign Out Success!');
})
.catch(() => this.$toast.show('Sign Out Failure!'));
}
2 changes: 1 addition & 1 deletion src/components/layout/top-navbar/top-navbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ <h2>
<md-menu-divider></md-menu-divider>

<md-menu-item>
<md-button aria-label="Sign Out" ng-click="nav.signout()">
<md-button aria-label="Sign Out" ng-click="nav.signOut($event)">
<span>{{ 'SETTINGS.SIGN_OUT' | translate }}</span>
</md-button>
</md-menu-item>
Expand Down
116 changes: 116 additions & 0 deletions src/components/layout/top-navbar/top-navbar.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import layoutModule from '../layout';
import topNavbarCtrl from './top-navbar.controller';
import app from '../../../index.js';

describe('User log out', function() {
let $rootScope;
let makeController;
let makeDeferred;
let AuthService;
let $translate;
let $mdDialog;
let $toast;
let $state;
let $auth;

beforeEach(angular.mock.module('app'));

beforeEach(inject(($q, _$rootScope_, _$toast_, _$state_, _$auth_, _AuthService_, _$mdDialog_, _$translate_) => {
$rootScope = _$rootScope_;

$toast = _$toast_;

$state = _$state_;

$auth = _$auth_;

$auth.isAuthenticated = () => true;

AuthService = _AuthService_;

$mdDialog = _$mdDialog_;

$translate = _$translate_;

makeDeferred = () => {
return $q.defer();
}

makeController = () => {
return new topNavbarCtrl($translate, $auth, $state, $toast, $mdDialog, AuthService);
};
}));
describe('when logout', function() {
it('should invoke showConfirmMessage()', function() {
const controller = makeController();
const showDialog = sinon.spy(controller, 'showConfirmMessage');
controller.signOut();
expect(showDialog.called).to.eq(true);
});
});
describe('when showConfirmMessage', function() {
it('should invoke $mdDialog.confirm', function() {
const controller = makeController();
const dialog = sinon.spy($mdDialog, 'confirm');
controller.signOut();
$rootScope.$digest();
expect(dialog.called).to.eq(true);
});
});
describe('when executedSignOut resolve', function() {
it('should invoke $auth.logout', function() {
const controller = makeController();
const AuthMock = sinon.mock(AuthService);
const deferred = makeDeferred();
AuthMock.expects('signOut').returns(deferred.promise);
deferred.resolve();
const auth = sinon.spy($auth, 'logout');
controller.executedSignOut();
$rootScope.$digest();
expect(auth.called).to.eq(true);
});
it('should invoke $state.go and called with auth.signin', function() {
const controller = makeController();
const AuthMock = sinon.mock(AuthService);
const deferred = makeDeferred();
AuthMock.expects('signOut').returns(deferred.promise);
deferred.resolve();
const state = sinon.spy($state, 'go');
controller.executedSignOut();
$rootScope.$digest();
expect(state).to.have.been.calledWith('auth.signin');
});
it('should invoke $toast.show and called with success message', function() {
const controller = makeController();
const AuthMock = sinon.mock(AuthService);
const deferred = makeDeferred();
AuthMock.expects('signOut').returns(deferred.promise);
deferred.resolve();
const toast = sinon.spy($toast, 'show');
controller.executedSignOut();
$rootScope.$digest();
expect(toast).to.have.been.calledWith('Sign Out Success!');
});
});
describe('when executedSignOut reject', function() {
it('should invoke $toast.show and call with fail message', function() {
const controller = makeController();
const signOutMock = sinon.mock(controller.$mdDialog);
const deferred = makeDeferred();
const authMock = sinon.mock(AuthService);
const authDeferred = makeDeferred();
signOutMock.expects('show').returns(deferred.promise);
deferred.reject();
authMock.expects('signOut').returns(authDeferred.promise);
authDeferred.reject();

const toast = sinon.spy($toast, 'show');
controller.executedSignOut();
$rootScope.$digest();
expect(toast).to.have.been.calledWith('Sign Out Failure!');
});
});
});



4 changes: 2 additions & 2 deletions src/styles/dialog.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* @author Jamie jamie.h@inwinstack.com
*/

.md-confirm-dialog-warn-theme md-dialog-actions button:last-child {
color: #FF6D00;
.md-default-theme md-dialog-actions button:last-child {
color: #FF6D00 !important;
}

md-dialog-content md-input-container.md-icon-right md-progress-circular {
Expand Down