Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .hound.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
eslint:
enabled: true
config_file: .eslintrc
config_file: .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function authenticate(authProvider) {
.then((result) => {
dispatcher.dispatch({
type: 'LOGIN_SUCCESS',
uid: result.user.uid,
user: result.user,
});
}, (error) => {
dispatcher.dispatch({
Expand Down
24 changes: 9 additions & 15 deletions app/api/NewsApi.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ const API_KEY = process.env.NEWS_API_KEY;
* makeRequest makes the call to the API using axios
* @function
* @param {string} path
* @param {string} lang
* @param {string} sourceKey
* @param {string} sortBy
* @returns {promise} Promise
*/
const makeRequest = (path, sourceKey = '', sortBy = '') => {
const makeRequest = (path, lang, sourceKey, sortBy) => {
let requestUrl = `${BASE_URL}/v1/`;

if (sourceKey && sortBy) {
requestUrl += `${path}?source=${sourceKey}&sortBy=${sortBy}&apiKey=${API_KEY}`;
} else {
requestUrl += `${path}?language=en`;
} else if (lang) {
requestUrl += `${path}?language=${lang}`;
}

return axios.get(requestUrl)
Expand All @@ -29,12 +30,8 @@ const makeRequest = (path, sourceKey = '', sortBy = '') => {
* @function
* @returns {func} makeRequest
*/
export const getSources = () => {
const path = 'sources';

return makeRequest(path)
.then(data => data.sources, error => error);
};
export const getSources = () => makeRequest('sources', 'en', undefined, undefined)
.then(res => res.sources, error => error);

/**
* getHeadlines retrieves the headlines from the API
Expand All @@ -43,9 +40,6 @@ export const getSources = () => {
* @param {string} sortBy
* @returns {func} makeRequest
*/
export const getHeadlines = (sourceKey = 'reddit-r-all', sortBy = 'top') => {
const path = 'articles';

return makeRequest(path, sourceKey, sortBy)
.then(data => data.articles, error => error);
};
export const getHeadlines =
(sourceKey = 'reddit-r-all', sortBy = 'top') => makeRequest('articles', undefined, sourceKey, sortBy)
.then(res => res.articles, error => error);
86 changes: 80 additions & 6 deletions app/components/Article.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import React, { Component } from 'react';
import AlertContainer from 'react-alert';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'AlertContainer' is defined but never used no-unused-vars
Missing file extension for "react-alert" import/extensions
Unable to resolve path to module 'react-alert' import/no-unresolved

import { hashHistory } from 'react-router';
import { Button, Container, Header, Segment, Divider, Dimmer, Loader } from 'semantic-ui-react';
import { Button, Container, Dimmer, Divider, Header, Loader, Segment } from 'semantic-ui-react';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'Button' is defined but never used no-unused-vars
'Container' is defined but never used no-unused-vars
'Dimmer' is defined but never used no-unused-vars
'Divider' is defined but never used no-unused-vars
'Header' is defined but never used no-unused-vars
'Loader' is defined but never used no-unused-vars
'Segment' is defined but never used no-unused-vars
Unable to resolve path to module 'semantic-ui-react' import/no-unresolved
Missing file extension for "semantic-ui-react" import/extensions


import ArticleStore from '../stores/ArticleStore.jsx';
import getArticle from '../actions/ArticleActions.jsx';
import { firebaseRef } from '../firebase/index.jsx';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unable to resolve path to module '../firebase/index.jsx' import/no-unresolved
Unexpected use of file extension "jsx" for "../firebase/index.jsx" import/extensions

import formatDate from '../helpers/DateFormatter.jsx';
import AuthStore from '../stores/AuthStore.jsx';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unexpected use of file extension "jsx" for "../stores/AuthStore.jsx" import/extensions
Unable to resolve path to module '../stores/AuthStore.jsx' import/no-unresolved

import ShareIcon from './ShareIcon.jsx';

const alertOptions = {
offset: 14,
position: 'bottom left',
theme: 'dark',
time: 4000,
transition: 'scale'
};

/**
* Article Component
* @class
Expand All @@ -21,9 +32,12 @@ export default class Article extends Component {

this.getArticle = this.getArticle.bind(this);
this.onClick = this.onClick.bind(this);
this.storeArticle = this.storeArticle.bind(this);

this.state = {
article: null,
userId: '',
disabled: false,
};
}

Expand All @@ -34,8 +48,11 @@ export default class Article extends Component {
*/
componentDidMount() {
const url = localStorage.getItem('url');
const user = Object.keys(AuthStore.user).length !== 0 ?
AuthStore.user : JSON.parse(localStorage.getItem('user'));
getArticle(url);

this.setUser(user);
ArticleStore.on('article_change', this.getArticle);
}

Expand All @@ -60,6 +77,18 @@ export default class Article extends Component {
});
}

/**
* setUser sets the state for userId.
* @method
* @param {Object} user
* @returns {void}
*/
setUser(user) {
this.setState({
userId: user.uid,
});
}

/**
* handleClick method for returning to the headlines.
* @method
Expand All @@ -69,21 +98,66 @@ export default class Article extends Component {
hashHistory.push('/headlines');
}

/**
* showAlert method for returning to the headlines.
* @method
* @returns {void}
*/
showAlert() {
this.msg.show('Article saved.');
}

/**
* storeArticle saves scraped article to the DB.
* @method
* @returns {void}
*/
storeArticle() {
const { article, userId } = this.state;
const articleToSave = {
title: article.title,
content: article.content,
date_published: formatDate(article.date_published),
lead_image_url: article.lead_image_url,
dek: article.dek,
url: article.url,
domain: article.domain,
excerpt: article.excerpt,
word_count: article.word_count,
direction: article.direction,
total_pages: article.total_pages,
rendered_pages: article.rendered_pages,
};

firebaseRef.child(`users/${userId}/articles`).push(articleToSave);
this.setState({
disabled: true,
});
this.showAlert();
}

/**
* render
* @method
* @returns {span} span
*/
render() {
const { article } = this.state;
const { article, disabled } = this.state;

return (
article ? (
<span>
<Container text textAlign="justified">
<AlertContainer ref={a => this.msg = a} {...alertOptions} />

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arrow function should not return assignment no-return-assign

<Container text textAlign='justified'>
<Segment raised>
<Button circular icon="arrow left" onClick={this.onClick} />
<Header as="h2">{article.title}</Header>
<Button circular icon='arrow left' onClick={this.onClick} />
<Button circular
disabled={disabled}
positive
icon='save'
onClick={this.storeArticle}
/>
<Header as='h2'>{article.title}</Header>
<small>{formatDate(article.date_published)}</small>
<ShareIcon url={article.url} title={article.title} />
<Divider hidden />
Expand All @@ -93,7 +167,7 @@ export default class Article extends Component {
</span>
) : (
<Dimmer active inverted>
<Loader size="large" inline="centered">Loading</Loader>
<Loader size='large' inline='centered'>Loading</Loader>
</Dimmer>
)
);
Expand Down
2 changes: 1 addition & 1 deletion app/components/Login.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import { Grid, Button, Icon, Segment, Header, Divider } from 'semantic-ui-react';

import { startLogin } from '../actions/LoginActions.jsx';
import { startLogin } from '../actions/AuthActions.jsx';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unexpected use of file extension "jsx" for "../actions/AuthActions.jsx" import/extensions
Unable to resolve path to module '../actions/AuthActions.jsx' import/no-unresolved

import { githubProvider, googleProvider } from '../firebase/index.jsx';

/**
Expand Down
2 changes: 1 addition & 1 deletion app/components/Sidebar.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import { Sidebar, Segment, Button, Menu, Grid, Icon, Dropdown, Dimmer, Loader } from 'semantic-ui-react';

import { startLogout } from '../actions/LoginActions.jsx';
import { startLogout } from '../actions/AuthActions.jsx';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unable to resolve path to module '../actions/AuthActions.jsx' import/no-unresolved
Unexpected use of file extension "jsx" for "../actions/AuthActions.jsx" import/extensions

import capitalise from '../helpers/Capitalise.jsx';
import createOptions from '../helpers/OptionsCreator.jsx';
import Headline from './Headline.jsx';
Expand Down
26 changes: 24 additions & 2 deletions app/stores/LoginStore.jsx → app/stores/AuthStore.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class LoginStore extends EventEmitter {
constructor() {
super();

this.user = {};
this.userId = '';
}

Expand All @@ -28,6 +29,26 @@ class LoginStore extends EventEmitter {
return this.userId;
}

/**
* setUser sets the user
* @param {Object} user
* @returns {void}
*/
setUser(user) {
this.user = user;
localStorage.setItem('user', JSON.stringify(user));
}

/**
* unsetUser clears user data and localStorage
* @returns {void}
*/
unsetUser() {
this.userId = '';
this.user = {};
localStorage.removeItem('user');
}

/**
* handleActions switches between actions and handle them accordingly
* @param {Object} action
Expand All @@ -36,10 +57,11 @@ class LoginStore extends EventEmitter {
handleActions(action) {
switch (action.type) {
case 'LOGIN_SUCCESS':
this.getUserId(action.uid);
this.getUserId(action.user.uid);
this.setUser(action.user);
break;
case 'LOGOUT_SUCCESS':
this.userId = '';
this.unsetUser();
break;

default: break;
Expand Down
34 changes: 34 additions & 0 deletions app/tests/stores/AuthStore.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import AuthStore from '../../stores/AuthStore.jsx';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unable to resolve path to module '../../stores/AuthStore.jsx' import/no-unresolved
Unexpected use of file extension "jsx" for "../../stores/AuthStore.jsx" import/extensions

import dispatcher from '../../dispatcher.jsx';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unable to resolve path to module '../../dispatcher.jsx' import/no-unresolved
Unexpected use of file extension "jsx" for "../../dispatcher.jsx" import/extensions


describe('Login Store', () => {
describe('successful login', () => {
beforeEach(() => {
dispatcher.dispatch({
type: 'LOGIN_SUCCESS',
user: {
uid: '1520',
displayName: 'Kennedy',
},
});
});

it('should set user and userId on successful login', () => {
expect(AuthStore.userId).to.equal('1520');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'expect' is not defined no-undef

expect(typeof AuthStore.user).to.equal('object');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'expect' is not defined no-undef

});
});

describe('successful logout', () => {
beforeEach(() => {
dispatcher.dispatch({
type: 'LOGOUT_SUCCESS',
});
});

it('should clear userId and localStorage on logout', () => {
expect(AuthStore.userId).to.equal('');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'expect' is not defined no-undef

expect(localStorage.getItem('user')).to.equal(null);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'expect' is not defined no-undef

});
});
});
29 changes: 0 additions & 29 deletions app/tests/stores/LoginStore.test.jsx

This file was deleted.

Loading