Skip to content

Commit 57dfb1d

Browse files
Merge pull request #52 from ekonstantinidis/participating
Settings - Participating Notifications
2 parents b92ec32 + 81dc252 commit 57dfb1d

File tree

11 files changed

+280
-7
lines changed

11 files changed

+280
-7
lines changed

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,11 @@
6969
"src/js/components/notification.js": true,
7070
"src/js/components/notifications.js": true,
7171
"src/js/components/repository.js": true,
72+
"src/js/components/settings.js": true,
7273
"src/js/components/footer.js": true,
7374
"src/js/stores/auth.js": true,
74-
"src/js/stores/notifications.js": true
75+
"src/js/stores/notifications.js": true,
76+
"src/js/stores/settings.js": true
7577
},
7678
"unmockedModulePathPatterns": [
7779
"node_modules/react",
@@ -111,6 +113,7 @@
111113
"octicons": "=2.2.0",
112114
"react": "=0.13.3",
113115
"react-router": "=0.13.3",
116+
"react-toggle": "=1.2.3",
114117
"react-tools": "=0.13.3",
115118
"reactify": "=1.1.1",
116119
"reflux": "=0.2.7",

src/js/__tests__/__mocks__/react-router.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,11 @@ Router.Link = React.createClass({
2222
}
2323
});
2424

25+
Router.State = {
26+
getPath: function () {
27+
return '/settings';
28+
},
29+
getCurrentPath: function () {}
30+
};
31+
2532
module.exports = Router;

src/js/__tests__/components/navigation.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,15 @@ describe('Test for Navigation', function () {
5050
expect(instance.refreshNotifications).toBeDefined();
5151
expect(instance.refreshDone).toBeDefined();
5252
expect(instance.logOut).toBeDefined();
53+
expect(instance.goBack).toBeDefined();
54+
expect(instance.goToSettings).toBeDefined();
5355
expect(instance.appQuit).toBeDefined();
5456

5557
var logoutIcon = TestUtils.scryRenderedDOMComponentsWithClass(instance, 'fa-sign-out');
5658
expect(logoutIcon.length).toBe(0);
5759

60+
var quitIcon = TestUtils.scryRenderedDOMComponentsWithClass(instance, 'fa-power-off');
61+
expect(quitIcon.length).toBe(1);
5862
});
5963

6064
it('Should load the navigation component for logged in users', function () {
@@ -72,6 +76,8 @@ describe('Test for Navigation', function () {
7276
expect(instance.refreshNotifications).toBeDefined();
7377
expect(instance.refreshDone).toBeDefined();
7478
expect(instance.logOut).toBeDefined();
79+
expect(instance.goBack).toBeDefined();
80+
expect(instance.goToSettings).toBeDefined();
7581
expect(instance.appQuit).toBeDefined();
7682

7783
var logoutIcon = TestUtils.scryRenderedDOMComponentsWithClass(instance, 'fa-sign-out');
@@ -124,4 +130,24 @@ describe('Test for Navigation', function () {
124130

125131
});
126132

133+
it('Should test the transitions', function () {
134+
135+
spyOn(Actions, 'getNotifications');
136+
137+
AuthStore.authStatus = function () {
138+
return true;
139+
};
140+
141+
var instance;
142+
React.withContext({router: new Router()}, function () {
143+
instance = TestUtils.renderIntoDocument(<Navigation />);
144+
});
145+
146+
expect(instance.componentDidMount).toBeDefined();
147+
148+
instance.goBack();
149+
instance.goToSettings();
150+
151+
});
152+
127153
});

src/js/__tests__/stores/settings.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*global jest, describe, it, expect, spyOn, beforeEach */
2+
3+
'use strict';
4+
5+
jest.dontMock('reflux');
6+
jest.dontMock('../../stores/settings.js');
7+
jest.dontMock('../../actions/actions.js');
8+
9+
describe('Tests for SettingsStore', function () {
10+
11+
var SettingsStore, Actions;
12+
13+
beforeEach(function () {
14+
15+
// Mock Electron's window.require
16+
window.require = function () {
17+
return {
18+
sendChannel: function () {
19+
return;
20+
}
21+
};
22+
};
23+
24+
// Mock localStorage
25+
window.localStorage = {
26+
item: false,
27+
getItem: function () {
28+
return this.item;
29+
},
30+
setItem: function (item) {
31+
this.item = item;
32+
}
33+
};
34+
35+
Actions = require('../../actions/actions.js');
36+
SettingsStore = require('../../stores/settings.js');
37+
});
38+
39+
it('should get the settings', function () {
40+
41+
spyOn(SettingsStore, 'trigger');
42+
43+
expect(SettingsStore.getSettings().participating).toBe(false);
44+
45+
});
46+
47+
it('should set a setting', function () {
48+
49+
spyOn(SettingsStore, 'trigger');
50+
51+
SettingsStore.onSetSetting('participating', true);
52+
53+
expect(SettingsStore.getSettings().participating).toBe(true);
54+
55+
});
56+
57+
});
58+
59+
describe('Tests for SettingsStore', function () {
60+
61+
var SettingsStore, Actions;
62+
63+
beforeEach(function () {
64+
65+
// Mock Electron's window.require
66+
window.require = function () {
67+
return {
68+
sendChannel: function () {
69+
return;
70+
}
71+
};
72+
};
73+
74+
// Mock localStorage
75+
window.localStorage = {
76+
item: false,
77+
getItem: function () {
78+
return '{}';
79+
},
80+
setItem: function (item) {
81+
this.item = item;
82+
}
83+
};
84+
85+
Actions = require('../../actions/actions.js');
86+
SettingsStore = require('../../stores/settings.js');
87+
});
88+
89+
it('should get the settings as string', function () {
90+
91+
spyOn(SettingsStore, 'trigger');
92+
93+
SettingsStore.getSettings();
94+
95+
});
96+
97+
});

src/js/actions/actions.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ var Actions = Reflux.createActions({
44

55
'login': {},
66
'logout': {},
7-
'getNotifications': {asyncResult: true}
7+
'getNotifications': {asyncResult: true},
8+
'setSetting': {}
89

910
});
1011

src/js/app.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ var Navigation = require('./components/navigation');
66
var Footer = require('./components/footer');
77
var LoginPage = require('./components/login');
88
var NotificationsPage = require('./components/notifications');
9+
var SettingsPage = require('./components/settings');
910

1011
var Route = Router.Route;
1112
var NotFoundRoute = Router.NotFoundRoute;
@@ -42,8 +43,9 @@ var NotFound = React.createClass({
4243
var routes = (
4344
<Route handler={App} path="/">
4445
<DefaultRoute handler={NotificationsPage} />
45-
<Route name="notifications" handler={NotificationsPage}/>
4646
<Route name="login" handler={LoginPage}/>
47+
<Route name="notifications" handler={NotificationsPage}/>
48+
<Route name="settings" handler={SettingsPage}/>
4749
<NotFoundRoute handler={NotFound}/>
4850
</Route>
4951
);

src/js/components/navigation.js

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
var React = require('react');
22
var Reflux = require('reflux');
3+
var Router = require('react-router');
4+
35
var ipc = window.require('ipc');
46

57
var Actions = require('../actions/actions');
68
var AuthStore = require('../stores/auth');
79

810
var Navigation = React.createClass({
911
mixins: [
12+
Router.State,
1013
Reflux.connect(AuthStore, 'authStatus'),
1114
Reflux.listenTo(Actions.getNotifications.completed, 'refreshDone'),
1215
Reflux.listenTo(Actions.getNotifications.failed, 'refreshDone')
@@ -42,18 +45,26 @@ var Navigation = React.createClass({
4245
this.setState( {loading: false } );
4346
},
4447

48+
goToSettings: function () {
49+
this.context.router.transitionTo('settings');
50+
},
51+
4552
logOut: function () {
4653
Actions.logout();
4754
this.context.router.transitionTo('login');
4855
ipc.sendChannel('update-icon', 'IconPlain');
4956
},
5057

58+
goBack: function () {
59+
this.context.router.transitionTo('notifications');
60+
},
61+
5162
appQuit: function () {
5263
ipc.sendChannel('app-quit');
5364
},
5465

5566
render: function () {
56-
var refreshIcon, logoutIcon;
67+
var refreshIcon, logoutIcon, backIcon, settingsIcon, quitIcon;
5768
var loadingClass = this.state.loading ? 'fa fa-refresh fa-spin' : 'fa fa-refresh';
5869

5970
if (this.state.authStatus) {
@@ -63,18 +74,34 @@ var Navigation = React.createClass({
6374
logoutIcon = (
6475
<i className='fa fa-sign-out' onClick={this.logOut} />
6576
);
77+
settingsIcon = (
78+
<i className='fa fa-cog' onClick={this.goToSettings} />
79+
);
80+
} else {
81+
quitIcon = (
82+
<i className='fa fa-power-off' onClick={this.appQuit} />
83+
);
84+
}
85+
if (this.getPath() === '/settings') {
86+
backIcon = (
87+
<i onClick={this.goBack} className='fa fa-chevron-left' />
88+
);
6689
}
6790

6891
return (
6992
<div className='container-fluid'>
7093
<div className='row navigation'>
71-
<div className='col-xs-4 left'>{refreshIcon}</div>
94+
<div className='col-xs-4 left'>
95+
{backIcon}
96+
{refreshIcon}
97+
</div>
7298
<div className='col-xs-4 logo'>
7399
<img className='img-responsive' src='images/logo-hor-white.png' />
74100
</div>
75101
<div className='col-xs-4 right'>
102+
{settingsIcon}
76103
{logoutIcon}
77-
<i className="fa fa-power-off" onClick={this.appQuit} />
104+
{quitIcon}
78105
</div>
79106
</div>
80107
</div>

src/js/components/settings.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
var React = require('react');
2+
var Toggle = require('react-toggle');
3+
4+
var ipc = window.require('ipc');
5+
6+
var Actions = require('../actions/actions');
7+
var SettingsStore = require('../stores/settings');
8+
9+
var SettingsPage = React.createClass({
10+
getInitialState: function () {
11+
return {
12+
participating: SettingsStore.getSettings().participating
13+
};
14+
},
15+
16+
toggleParticipating: function (event) {
17+
Actions.setSetting('participating', event.target.checked);
18+
},
19+
20+
appQuit: function () {
21+
ipc.sendChannel('app-quit');
22+
},
23+
24+
render: function () {
25+
return (
26+
<div className="container-fluid main-container settings">
27+
<div className='row'>
28+
<div className='col-xs-8'>Show only participating</div>
29+
<div className='col-xs-4'>
30+
<Toggle
31+
defaultChecked={this.state.participating}
32+
onChange={this.toggleParticipating} />
33+
</div>
34+
</div>
35+
<div className='row'>
36+
<button
37+
className='btn btn-block btn-danger btn-close'
38+
onClick={this.appQuit}>
39+
<i className="fa fa-power-off" />
40+
Quit Gitify
41+
</button>
42+
</div>
43+
</div>
44+
);
45+
}
46+
});
47+
48+
module.exports = SettingsPage;

src/js/stores/notifications.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var _ = require('underscore');
44
var Reflux = require('reflux');
55
var Actions = require('../actions/actions');
66
var apiRequests = require('../utils/api-requests');
7+
var SettingsStore = require('../stores/settings');
78

89
var NotificationsStore = Reflux.createStore({
910
listenables: Actions,
@@ -22,9 +23,11 @@ var NotificationsStore = Reflux.createStore({
2223

2324
onGetNotifications: function () {
2425
var self = this;
26+
var participating = SettingsStore.getSettings().participating;
2527

2628
apiRequests
27-
.getAuth('https://api.github.com/notifications')
29+
.getAuth('https://api.github.com/notifications?participating=' +
30+
(participating ? 'true' : 'false'))
2831
.end(function (err, response) {
2932
if (response && response.ok) {
3033
// Success - Do Something.

src/js/stores/settings.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
var Reflux = require('reflux');
2+
var Actions = require('../actions/actions');
3+
4+
var SettingsStore = Reflux.createStore({
5+
listenables: Actions,
6+
7+
init: function () {
8+
var settings = window.localStorage.getItem('settings');
9+
10+
if (!settings) {
11+
settings = {
12+
'participating': false
13+
};
14+
}
15+
16+
if (settings[0] === '{') {
17+
settings = JSON.parse(settings);
18+
}
19+
20+
this._settings = settings;
21+
},
22+
23+
getSettings: function () {
24+
return this._settings;
25+
},
26+
27+
onSetSetting: function (setting, value) {
28+
this._settings[setting] = value;
29+
window.localStorage.setItem('settings', JSON.stringify(this._settings));
30+
this.trigger(this._settings);
31+
}
32+
33+
});
34+
35+
module.exports = SettingsStore;

0 commit comments

Comments
 (0)