Skip to content

Commit 3df1644

Browse files
Merge pull request #215 from ekonstantinidis/starred-already
186 - Hide "Star on GitHub"
2 parents 7dd24ef + 820458e commit 3df1644

File tree

9 files changed

+129
-12
lines changed

9 files changed

+129
-12
lines changed

src/js/__tests__/actions/index.js

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { expect } from 'chai';
22
import nock from 'nock';
3-
import { apiMiddleware } from 'redux-api-middleware';
3+
import { apiMiddleware, ApiError } from 'redux-api-middleware';
44
import configureMockStore from 'redux-mock-store';
5+
6+
import Constants from '../../utils/constants';
57
import * as actions from '../../actions';
68

79
const middlewares = [ apiMiddleware ];
@@ -186,7 +188,6 @@ describe('actions/index.js', () => {
186188

187189
});
188190

189-
190191
it('should mark a repository\'s notifications as read with success', () => {
191192
const loginId = 'ekonstantinidis';
192193
const repoId = 'gitify';
@@ -249,6 +250,44 @@ describe('actions/index.js', () => {
249250

250251
});
251252

253+
it('should check if the user has starred the repository', () => {
254+
nock('https://api.github.com/')
255+
.get(`/user/starred/${Constants.REPO_SLUG}`)
256+
.reply(200);
257+
258+
const expectedActions = [
259+
{ type: actions.HAS_STARRED_REQUEST, payload: undefined, meta: undefined },
260+
{ type: actions.HAS_STARRED_SUCCESS, payload: undefined, meta: undefined }
261+
];
262+
263+
const store = createMockStore({ response: [] }, expectedActions);
264+
265+
return store.dispatch(actions.checkHasStarred())
266+
.then(() => { // return of async actions
267+
expect(store.getActions()).to.eql(expectedActions);
268+
});
269+
270+
});
271+
272+
it('should check if the user has starred the repository', () => {
273+
nock('https://api.github.com/')
274+
.get(`/user/starred/${Constants.REPO_SLUG}`)
275+
.reply(404);
276+
277+
const apiError = new ApiError(404, 'Not Found', undefined);
278+
const expectedActions = [
279+
{ type: actions.HAS_STARRED_REQUEST, payload: undefined, meta: undefined },
280+
{ type: actions.HAS_STARRED_FAILURE, payload: apiError, error: true, meta: undefined }
281+
];
282+
283+
const store = createMockStore({ response: [] }, expectedActions);
284+
285+
return store.dispatch(actions.checkHasStarred())
286+
.then(() => { // return of async actions
287+
expect(store.getActions()).to.eql(expectedActions);
288+
});
289+
290+
});
252291

253292
it('should search the notifications with a query', () => {
254293

src/js/__tests__/reducers/settings.js

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import { expect } from 'chai';
22
import reducer from '../../reducers/settings';
3-
import { UPDATE_SETTING } from '../../actions';
3+
import { UPDATE_SETTING, HAS_STARRED_SUCCESS, HAS_STARRED_FAILURE } from '../../actions';
44

55
describe('reducers/settings.js', () => {
66
const initialState = {
77
participating: false,
88
playSound: true,
99
showNotifications: true,
1010
markOnClick: false,
11-
openAtStartup: false
11+
openAtStartup: false,
12+
hasStarred: false
1213
};
1314

1415
it('should return the initial state', () => {
@@ -42,4 +43,31 @@ describe('reducers/settings.js', () => {
4243
});
4344

4445
});
46+
47+
it('should handle HAS_STARRED_SUCCESS', () => {
48+
49+
const actionParticipating = {
50+
type: HAS_STARRED_SUCCESS
51+
};
52+
53+
expect(reducer(undefined, actionParticipating)).to.eql({
54+
...initialState,
55+
hasStarred: true
56+
});
57+
58+
});
59+
60+
it('should handle HAS_STARRED_SUCCESS', () => {
61+
62+
const actionParticipating = {
63+
type: HAS_STARRED_FAILURE
64+
};
65+
66+
expect(reducer(undefined, actionParticipating)).to.eql({
67+
...initialState,
68+
hasStarred: false
69+
});
70+
71+
});
72+
4573
});

src/js/actions/index.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,27 @@ export function markRepoNotifications(loginId, repoId, repoFullName) {
115115
};
116116

117117

118+
// Starred
119+
120+
export const HAS_STARRED_REQUEST = 'HAS_STARRED_REQUEST';
121+
export const HAS_STARRED_SUCCESS = 'HAS_STARRED_SUCCESS';
122+
export const HAS_STARRED_FAILURE = 'HAS_STARRED_FAILURE';
123+
export function checkHasStarred() {
124+
return {
125+
[CALL_API]: {
126+
endpoint: `https://api.github.com/user/starred/${Constants.REPO_SLUG}`,
127+
method: 'GET',
128+
headers: {
129+
'Accept': 'application/json',
130+
'Cache-Control': 'no-cache',
131+
'Content-Type': 'application/json'
132+
},
133+
types: [HAS_STARRED_REQUEST, HAS_STARRED_SUCCESS, HAS_STARRED_FAILURE]
134+
}
135+
};
136+
};
137+
138+
118139
// Search
119140

120141
export const SEARCH_NOTIFICATIONS = 'SEARCH_NOTIFICATIONS';

src/js/components/login.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export class LoginPage extends React.Component {
7575
return (
7676
<div className="container-fluid main-container login">
7777
<div className="row">
78-
<div className="col-xs-offset-2 col-xs-8">
78+
<div className="offset-xs-2 col-xs-8">
7979
<img className="img-responsive logo" src="images/gitify-logo-outline-dark.png" />
8080
<div className="desc">GitHub Notifications<br />in your menu bar.</div>
8181
<button className="btn btn-lg btn-block" onClick={this.authGithub.bind(this)}>

src/js/components/notifications.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export class NotificationsPage extends React.Component {
6262
})}
6363
</ReactCSSTransitionGroup>
6464

65-
{!_.isEmpty(groupedNotifications) ? (
65+
{!_.isEmpty(groupedNotifications) && !this.props.hasStarred ? (
6666
<div className="fork" onClick={this.openBrowser}>
6767
<i className="fa fa-github" /> Star Gitify on GitHub
6868
</div>
@@ -74,6 +74,7 @@ export class NotificationsPage extends React.Component {
7474

7575
function mapStateToProps(state) {
7676
return {
77+
hasStarred: state.settings.hasStarred,
7778
failed: state.notifications.failed,
7879
notifications: state.notifications.response,
7980
searchQuery: state.searchFilter.query

src/js/middleware/requests.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { CALL_API, isRSAA } from 'redux-api-middleware';
2-
import { NOTIFICATIONS_REQUEST, MARK_NOTIFICATION_REQUEST, MARK_REPO_NOTIFICATION_REQUEST } from '../actions';
2+
import {
3+
HAS_STARRED_REQUEST,
4+
NOTIFICATIONS_REQUEST,
5+
MARK_NOTIFICATION_REQUEST,
6+
MARK_REPO_NOTIFICATION_REQUEST
7+
} from '../actions';
38

49
export default store => next => action => {
510
if (!isRSAA(action)) {
@@ -12,6 +17,7 @@ export default store => next => action => {
1217
const endpoint = action[CALL_API].endpoint + '?participating=';
1318
action[CALL_API].endpoint = endpoint + (settings.participating ? 'true' : 'false');
1419

20+
case HAS_STARRED_REQUEST:
1521
case NOTIFICATIONS_REQUEST:
1622
case MARK_NOTIFICATION_REQUEST:
1723
case MARK_REPO_NOTIFICATION_REQUEST:

src/js/reducers/settings.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import {
2-
UPDATE_SETTING
2+
UPDATE_SETTING,
3+
HAS_STARRED_SUCCESS,
4+
HAS_STARRED_FAILURE
35
} from '../actions';
46

57
const initialState = {
68
participating: false,
79
playSound: true,
810
showNotifications: true,
911
markOnClick: false,
10-
openAtStartup: false
12+
openAtStartup: false,
13+
hasStarred: false
1114
};
1215

1316
export default function reducer(state = initialState, action) {
@@ -17,6 +20,16 @@ export default function reducer(state = initialState, action) {
1720
...state,
1821
[action.setting]: action.value
1922
};
23+
case HAS_STARRED_SUCCESS:
24+
return {
25+
...state,
26+
hasStarred: true
27+
};
28+
case HAS_STARRED_FAILURE:
29+
return {
30+
...state,
31+
hasStarred: false
32+
};
2033
default:
2134
return state;
2235
}

src/js/store/configureStore.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@ import * as storage from 'redux-storage';
55
import createEngine from 'redux-storage-engine-localstorage';
66
import filter from 'redux-storage-decorator-filter';
77

8-
import { fetchNotifications, UPDATE_SETTING, LOGIN_SUCCESS, LOGOUT } from '../actions';
8+
import { checkHasStarred, fetchNotifications, UPDATE_SETTING, LOGIN_SUCCESS, LOGOUT } from '../actions';
99
import constants from '../utils/constants';
1010
import notifications from '../middleware/notifications';
1111
import settings from '../middleware/settings';
1212
import requests from '../middleware/requests';
1313
import rootReducer from '../reducers';
1414

1515
export default function configureStore(initialState) {
16-
const engine = filter(createEngine(constants.STORAGE_KEY), ['settings', ['auth', 'token']]);
16+
const engine = filter(
17+
createEngine(constants.STORAGE_KEY),
18+
['settings', ['auth', 'token']],
19+
[['settings', 'hasStarred']]
20+
);
1721
const storageMiddleware = storage.createMiddleware(engine, [], [UPDATE_SETTING, LOGIN_SUCCESS, LOGOUT]);
1822

1923
const createStoreWithMiddleware = applyMiddleware(
@@ -32,7 +36,10 @@ export default function configureStore(initialState) {
3236
.then(function (newState) {
3337
// Check if the user is logged in
3438
const isLoggedIn = store.getState().auth.token !== null;
35-
if (isLoggedIn) { store.dispatch(fetchNotifications()); }
39+
if (isLoggedIn) {
40+
store.dispatch(checkHasStarred());
41+
store.dispatch(fetchNotifications());
42+
}
3643
});
3744

3845
return store;

src/js/utils/constants.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ let constants = {
44
CLIENT_SECRET: '9670de733096c15322183ff17ed0fc8704050379',
55
SCOPE: ['user:email', 'notifications'],
66

7+
REPO_SLUG: 'ekonstantinidis/gitify',
8+
79
// Storage
810
STORAGE_KEY: 'gitify-storage',
911

0 commit comments

Comments
 (0)