Skip to content

Commit

Permalink
feat(articles): create new article
Browse files Browse the repository at this point in the history
- post a new article

[delivers #161966572]
  • Loading branch information
SnyderMbishai committed Jan 30, 2019
1 parent 71520fb commit 594f6cb
Show file tree
Hide file tree
Showing 19 changed files with 627 additions and 67 deletions.
53 changes: 53 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"jest-mock": "^23.2.0",
"moment": "^2.24.0",
"js-cookie": "^2.2.0",
"jsdom": "^13.2.0",
"moxios": "^0.4.0",
"prop-types": "^15.6.2",
"react": "^16.7.0",
Expand All @@ -27,6 +28,7 @@
"react-router-dom": "^4.3.1",
"react-scripts": "2.1.3",
"react-semantic-toasts": "^0.4.1",
"react-simplemde-editor": "^3.6.22",
"react-test-renderer": "^16.7.0",
"redux": "^4.0.1",
"redux-devtools-extension": "^2.13.7",
Expand All @@ -37,7 +39,8 @@
"semantic-ui-css": "^2.4.1",
"semantic-ui-react": "^0.84.0",
"toastr": "^2.1.4",
"sfcookies": "^1.0.2"
"sfcookies": "^1.0.2",
"simplemde": "^1.11.2"
},
"scripts": {
"start": "react-scripts start",
Expand Down
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
<script src="https://widget.cloudinary.com/v2.0/global/all.js" type="text/javascript"></script>
<script src="https://widget.cloudinary.com/v2.0/global/all.js" type="text/javascript"></script>
</html>
5 changes: 5 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import LoginContainer from './components/Authentication/Login/LoginContainer';

import Profile from './containers/ProfileContainer';

import CreateArticleFormContainer from './components/Articles/CreateArticleFormContainer';

class App extends Component {
render() {
return (
Expand All @@ -24,6 +26,9 @@ class App extends Component {
<Route path="/articles" component={ArticleContainerComponent} exact />
<Route path="/register" component={RegistrationPageComponent} exact />
<Route path="/profile" exact component={Profile} />
<Route path="/new_article" component={CreateArticleFormContainer} exact />
<Route exact path="/login" component={LoginContainer} />
<Route exact path="/articles/:slug" component={ViewSingleArticleComponent} />
<Route component={Error} />
</Switch>
</BrowserRouter>
Expand Down
98 changes: 68 additions & 30 deletions src/actions/__tests__/ArticlesActions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,37 +51,30 @@ const dummyData = {
},
};

const articlesArray = [
{
id: 1,
title: 'How to train your dragon3',
description: 'Ever wonder how?',
body: 'You have to believe',
author: {
username: 'Jacob',
email: 'jake@jake.jake',
created_at: '2019-01-16T11:22:08.569092Z',
bio: '',
country: '',
avatar: 'https://libertv.com/wp-content/uploads/2018/03/user-avatar-placeholder-1.png',
phone: '',
website: '',
},
tags: [],
like: {
likeCount: 0,
},
dislike: {
dislikeCount: 0,
const articlesArray = dummyData.results.articles;

const articleData = {
title: 'Hello World',
description: 'Hello world',
body: 'Kenya',
author: 'Author',
};

const createExpectedRes = {
token: 'ertyuiop[poihgfdsxcvbnjmnbvcvbn',
message: "The article 'Hello hello' has been successfully created.",
};
const errorExpectedRes = {
token: 'ertyuiop[poihgfdsxcvbnjmnbvcvbn',
response: {
data: {
detail: {
message: "The article 'Hello hello' has been successfully created.",
},
},
rating: 0,
image: '',
article_slug: 'how-to-train-your-dragon3',
created_at: '2019-01-16T11:22:39.439567Z',
updated_at: '2019-01-16T11:22:39.439615Z',
favorite: [],
},
];
};

describe('getArticles actions', () => {
beforeEach(() => {
moxios.install();
Expand All @@ -107,6 +100,24 @@ describe('getArticles actions', () => {
expect(store.getActions()).toEqual(expectedActions);
});
});
it('creates CREATE_ARTICLES_SUCCESS after successfully creating an article', () => {
moxios.wait(() => {
const request = moxios.requests.mostRecent();
request.respondWith({
status: 201,
response: createExpectedRes,
});
});
const message = "The article 'Hello hello' has been successfully created.";
const expectedActions = [
{ type: types.CREATE_ARTICLE, articleData },
{ type: types.CREATE_ARTICLE_SUCCESS, response: message },
];
const store = mockStore(message);
return store.dispatch(actions.createArticle(articleData)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
});
});
});

describe('Article Actions types', () => {
Expand Down Expand Up @@ -135,7 +146,6 @@ describe('Article Actions types', () => {
});
});


describe('Pagination', () => {
afterEach = (
() => mock.restore()
Expand Down Expand Up @@ -211,3 +221,31 @@ describe('Get paginated data', () => {
});
});
});
describe('Article creation Actions types', () => {
describe('dispatch create', () => {
it('should create a request action', () => {
const expectedAction = {
type: types.CREATE_ARTICLE,

};
expect(actions.create()).toEqual(expectedAction);
});

it('should create a success create action', () => {
const expectedAction = {
type: types.CREATE_ARTICLE_SUCCESS,
response: articleData,
};
expect(actions.createSuccess(articleData)).toEqual(expectedAction);
});

it('should create a fail create action', () => {
const message = 'error';
const expectedAction = {
type: types.CREATE_ARTICLE_FAILS,
error: message,
};
expect(actions.createFail(message)).toEqual(expectedAction);
});
});
});
7 changes: 5 additions & 2 deletions src/actions/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ export const USER_REGISTRATION_FAIL = 'USER_REGISTRATION_FAIL';
export const USER_REGISTRATION_SUCCESS = 'USER_REGISTRATION_SUCCESS';
export const USER_REGISTRATION_FAIL_PASSWORD = 'USER_REGISTRATION_FAIL_PASSWORD';
export const FETCH_ARTICLES = 'FETCH_ARTICLES';
export const FETCH_ARTICLES_SUCCESS = 'FETCH_ARTICLES';
export const FETCH_ARTICLES_FAILS = 'FETCH_ARTICLES';
export const LOGIN_ACTION = 'LOGIN_ACTION';
export const LOGIN_SUCCESSFUL = 'LOGIN_SUCCESSFUL';
export const LOGIN_REJECTED = 'LOGIN_REJECTED';
Expand All @@ -20,3 +18,8 @@ export const SEARCH_FAIL = 'SEARCH_FAIL';
export const UPDATED_ARTICLES = 'UPDATED_ARTICLES';
export const PAGE = 'GET_PAGES_COUNT';
export const NEXT_PAGE = 'NEXT_PAGE';
export const FETCH_ARTICLES_SUCCESS = 'FETCH_ARTICLES_SUCCESS';
export const FETCH_ARTICLES_FAILS = 'FETCH_ARTICLES_FAILS';
export const CREATE_ARTICLE = 'CREATE_ARTICLE';
export const CREATE_ARTICLE_SUCCESS = 'CREATE_ARTICLE_SUCCESS';
export const CREATE_ARTICLE_FAILS = 'CREATE_ARTICLE_FAILS';
52 changes: 41 additions & 11 deletions src/actions/articleActions.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,54 @@
import axios from 'axios';
import {
FETCH_ARTICLES, FETCH_ARTICLES_SUCCESS, FETCH_ARTICLES_FAILS, PAGE, NEXT_PAGE,
} from './actionTypes';
import Cookies from 'js-cookie';

import * as types from './actionTypes';

export const fetchAllArticles = () => (
{
type: FETCH_ARTICLES,
type: types.FETCH_ARTICLES,
}
);

export const fetchArticlesSuccess = payload => (
{
type: FETCH_ARTICLES_SUCCESS,
type: types.FETCH_ARTICLES_SUCCESS,
payload,
}
);

export const fetchPagesCount = payload => (
{
type: PAGE,
type: types.PAGE,
payload,
}
);

export const fetchArticleFails = errorMessage => (
export const fetchArticleFails = error => (
{
type: FETCH_ARTICLES_FAILS,
errorMessage,
type: types.FETCH_ARTICLES_FAILS,
error,
}
);
export const getNextPage = () => (
{
type: NEXT_PAGE,
type: types.NEXT_PAGE,
}
);


export const create = articleData => ({
type: types.CREATE_ARTICLE,
articleData,
});
export const createFail = error => ({
type: types.CREATE_ARTICLE_FAILS,
error,
});

export const createSuccess = response => ({
type: types.CREATE_ARTICLE_SUCCESS,
response,
});

export function fetchArticles() {
return (dispatch) => {
dispatch(fetchAllArticles());
Expand Down Expand Up @@ -63,3 +76,20 @@ export function getPage(page) {
.catch(errorMessage => dispatch(fetchArticleFails(errorMessage)));
};
}
const token = Cookies.get('access_token');

export const createArticle = articleData => (dispatch) => {
dispatch(create(articleData));
return axios.post('https://ah-technocrats.herokuapp.com/api/articles/', articleData, {
headers: {
'Content-Type': 'application/json',
Authorization: `Token ${token}`,
},
})
.then(res => dispatch(createSuccess(res.data.message)))
.catch((error) => {
dispatch(createFail(error));
});
};

export default fetchArticles;
2 changes: 1 addition & 1 deletion src/components/Articles/AllArticlesComponent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ let number;
const AllArticlesComponent = ({
articles, pagination, getNewPage,
}) => (
<Container>
<Container className="allArticles">
<div className="space">
<div className="ui header medium">
Latest Articles
Expand Down
Loading

0 comments on commit 594f6cb

Please sign in to comment.