Skip to content

Commit

Permalink
feature(create articles): users can post articles
Browse files Browse the repository at this point in the history
- Enable users to post an article

[Delivers #160609518]
  • Loading branch information
samuelbwambale committed Nov 9, 2018
1 parent 6ce122c commit 80dc0a5
Show file tree
Hide file tree
Showing 29 changed files with 486 additions and 13,642 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"ajv": "^6.5.4",
"axios": "^0.18.0",
"axios-mock-adapter": "^1.15.0",
"draft-js": "^0.10.5",
"enzyme": "^3.7.0",
"enzyme-adapter-react-16": "^1.6.0",
"history": "^4.7.2",
Expand All @@ -16,6 +17,7 @@
"react-facebook-login": "^4.1.1",
"react-google-login": "^3.2.1",
"react-notify-toast": "^0.5.0",
"react-quill": "^1.3.2",
"react-redux": "^5.1.0",
"react-router-dom": "^4.3.1",
"react-scripts": "2.0.5",
Expand Down
4 changes: 3 additions & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4"
crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
<link rel="stylesheet" href="%PUBLIC_URL%/style.css">

<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
Expand Down
3 changes: 3 additions & 0 deletions public/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.ql-container.ql-snow {
border: none!important;
}
8 changes: 8 additions & 0 deletions src/actions/actionCreators.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
SOCIAL_LOGIN_INITIATED,
SOCIAL_LOGIN_SUCCESS,
CREATE_ARTICLE_SUCCESS,
} from './types';

export const socialLoginInitiated = () => ({
Expand All @@ -11,3 +12,10 @@ export const socialLoginInitiated = () => ({
export const socialLoginSuccess = () => ({
type: SOCIAL_LOGIN_SUCCESS,
});

export const createArticle = (payload) => ({
type: CREATE_ARTICLE_SUCCESS,
payload,
});

export default createArticle;
20 changes: 20 additions & 0 deletions src/actions/articleActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { toast } from 'react-toastify';
import { axiosInstance } from '../config/axiosInstance';
import { createArticle } from './actionCreators';

export const postArticle = (postData) => dispatch => {
toast.dismiss();
axiosInstance
.post('/api/articles/', postData)
.then(response => {
dispatch(createArticle(true));
toast.success(
response.statusText,
{ autoClose: 3500, hideProgressBar: true },
{
position: toast.POSITION.TOP_CENTER,
},
);
});
};
export default postArticle;
4 changes: 4 additions & 0 deletions src/actions/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ export const LOGIN_USER_SUCCESS = 'LOGIN_USER_SUCCESS';
export const LOGIN_USER_ERROR = 'LOGIN_USER_ERROR';
export const SOCIAL_LOGIN_INITIATED = 'SOCIAL_LOGIN_INITIATED';
export const SOCIAL_LOGIN_SUCCESS = 'SOCIAL_LOGIN_SUCCESS';
export const GET_ALL_ARTICLES_INITIATED = 'GET_ALL_ARTICLES_INITIATED';
export const GET_ALL_ARTICLES_SUCCESS = 'GET_ALL_ARTICLES_SUCCESS';
export const GET_ALL_ARTICLES_ERROR = 'GET_ALL_ARTICLES_ERROR';
export const CREATE_ARTICLE_SUCCESS = 'CREATE_ARTICLE_SUCCESS';
2 changes: 1 addition & 1 deletion src/actions/userActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
socialLoginInitiated,
socialLoginSuccess,
} from './actionCreators';
import axiosInstance from '../config/axiosInstance';

import axiosInstance from '../config/axiosInstance';

export const fetchUsers = (postData) => dispatch => {
toast.dismiss();
Expand Down
36 changes: 32 additions & 4 deletions src/assets/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,12 @@ header.uvp {
margin-top: -64px !important;
padding-top: 64px;
}

.lp-intro {
margin-top: 36px;
}

.lp-intro {
margin-top: 36px;
}
.registerForm {
margin: 120px auto;
width: 400px;
Expand All @@ -111,7 +112,6 @@ header.uvp {
box-shadow: 0 15px 25px rgba(0, 0, 0, .5);
border-radius: 10px;
}

.forgot-password{
color: firebrick;
}
Expand All @@ -133,7 +133,6 @@ header.uvp {
font-family: Roboto;
transition: background-color .3s,border-color .3s;
}

.facebook{
font-family: Roboto;
font-weight: bold;
Expand All @@ -151,3 +150,32 @@ header.uvp {
display: inline-block;
border:solid 1px #4c69ba;
}
.forgot-password{
color: firebrick;
}
.article-img{
width: 75%;
}
.btn-long{
width: 100%;
}
.quill-height{
height: 350px;
}
.clear-box{
border: none;
width: 100%;
}
.clear-box:focus{
outline: none;
border-bottom: 2px solid #ece9e9;
}
.very-big-font{
font-size: 40px;
}
.bigger-font{
font-size: 20px;
}
.m-r-10{
margin-right: 10px;
}
Binary file added src/assets/images/a_200.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/article.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
Binary file added src/assets/images/user.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/components/Articles/ArticlesList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

128 changes: 128 additions & 0 deletions src/components/Articles/NewArticle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
import { postArticle } from '../../actions/articleActions';

export class NewArticle extends Component {
editorModules = {
toolbar: [
[{ header: [1, 2, 3, 4, false] }],
['bold', 'italic', 'underline', 'strike', 'blockquote'],
[{ size: ['14px', '16px', '18px'] }],
[{ list: 'ordered' }, { list: 'bullet' }, { indent: '-1' }, { indent: '+1' }],
['link', 'image'],
['clean'],
],
};

constructor(props) {
super(props);
this.state = {
title: '',
description: '',
body: '',
};
}

componentWillReceiveProps(nextProps) {
if (nextProps.createArticleSuccess === true) {
const { history } = this.props;
history.push('/');
}
}

handleSubmit = event => {
event.preventDefault();
const { title, description, body } = this.state;
const payload = {
article: {
title,
description,
body,
},
};
const { addArticle } = this.props;
addArticle(payload);
}

resetForm = () => {
this.setState({
title: '',
description: '',
body: '',
});
};

handleChange = event => {
const { name, value } = event.target;
this.setState({ [name]: value });
}

handleEditorChange = (value) => {
this.setState({ body: value });
}

render() {
const { title, description, body } = this.state;
return (
<div className="container" style={{ paddingTop: '50px' }}>
<div className="row">
<div className="col-12">
<form id="add-article-form" onSubmit={this.handleSubmit}>
<div className="container col-sm-12 col-md-8">
<div className="form-group mt-2">
<div className="input-group mb-2">
<input type="text" name="title" className="clear-box very-big-font" placeholder="Title" id="title" value={title} onChange={this.handleChange} required />
</div>
</div>
<div className="form-group">
<div className="input-group mb-2">
<input type="text" name="description" className="clear-box bigger-font" placeholder="Description" id="description" value={description} onChange={this.handleChange} required />
</div>
</div>
<div className="form-group">
<div className="text-editor">
<div>
<ReactQuill
id="text-editor"
modules={this.editorModules}
theme="snow"
className="quill-height"
value={body}
onChange={this.handleEditorChange}
required
/>
</div>
</div>
</div>
<div className="mt-5">
<button type="submit" className="btn btn-primary m-r-10">Save</button>
<button type="button" id="clear-button" className="btn btn-outline-warning m-r-10" onClick={this.resetForm}>Clear</button>
</div>
</div>
</form>
</div>
</div>
</div>
);
}
}

NewArticle.propTypes = {
addArticle: PropTypes.func.isRequired,
history: PropTypes.object.isRequired,
createArticleSuccess: PropTypes.bool.isRequired,
};


const mapStateToProps = (state) => ({
articlesPayload: state.article.articlesPayload,
createArticleSuccess: state.article.createArticleSuccess,
});

export default connect(
mapStateToProps,
{ addArticle: postArticle },
)(NewArticle);
Empty file.
Empty file.
Loading

0 comments on commit 80dc0a5

Please sign in to comment.