Skip to content

Commit

Permalink
feat(articles): delete articles
Browse files Browse the repository at this point in the history
this feature will enable users to delete articles they have authored

[Finishes #161776758]
  • Loading branch information
mendozabree committed Nov 20, 2018
1 parent 021f645 commit ecc3984
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 44 deletions.
6 changes: 6 additions & 0 deletions src/actions/actionCreators.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
GET_ALL_ARTICLES_INITIATED,
LIKE_DISLIKE_SUCCESS,
LIKE_DISLIKE_ERROR,
DELETE_ARTICLE_SUCCESS,
} from './types';

export const socialLoginInitiated = () => ({
Expand Down Expand Up @@ -81,3 +82,8 @@ export const likeDislikeError = payload => ({
type: LIKE_DISLIKE_ERROR,
payload,
});

export const deleteArticleSuccess = payload => ({
type: DELETE_ARTICLE_SUCCESS,
payload,
});
20 changes: 16 additions & 4 deletions src/actions/articleActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ import {
getArticlesInitiated,
likeDislikeSuccess,
likeDislikeError,
deleteArticleSuccess,
} from './actionCreators';

export const postArticle = postData => dispatch => {
toast.dismiss();
dispatch(createArticleInititated(true));
return axiosInstance
axiosInstance
.post('/api/articles/', postData)
.then(response => {
dispatch(createArticleSuccess(true));
Expand Down Expand Up @@ -70,9 +71,8 @@ export const fetchArticles = () => dispatch => {
};

export const fetchSpecificArticle = slug => dispatch => {
dispatch(getArticlesInitiated(true));
return axiosInstance
.get(`/api/articles/${slug}`)
axiosInstance
.get(`/api/articles/${slug}/`)
.then((response) => {
dispatch(getSpecificArticle(response.data));
});
Expand Down Expand Up @@ -113,3 +113,15 @@ export const likeDislike = (payload, slug) => dispatch => {
return toast.error(error.response.data.detail, { autoClose: false, hideProgressBar: true });
});
};

export const deleteArticle = slug => dispatch => {
axiosInstance
.delete(`/api/articles/${slug}/`)
.then(() => {
dispatch(deleteArticleSuccess(true));
toast.success(
'The article was deleted!',
{ autoClose: 3500, hideProgressBar: true },
);
});
};
1 change: 1 addition & 0 deletions src/actions/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export const GET_USER_ARTICLES_SUCCESS = 'GET_USER_ARTICLES_SUCCESS';
export const GET_ALL_ARTICLES_INITIATED = 'GET_ALL_ARTICLES_INITIATED';
export const LIKE_DISLIKE_SUCCESS = 'LIKE_DISLIKE_SUCCESS';
export const LIKE_DISLIKE_ERROR = 'LIKE_DISLIKE_ERROR';
export const DELETE_ARTICLE_SUCCESS = 'DELETE_ARTICLE_SUCCESS';
15 changes: 15 additions & 0 deletions src/assets/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ header.uvp {
font-size: 14px;
border-radius: 6px;
margin-right: 10px;
outline: #24292e;
}
.btn-edit:hover{
background-color: rgb(141, 189, 67);
Expand All @@ -437,6 +438,7 @@ header.uvp {
background-color: #eceff1;
color: black;
font-size: 14px;
outline: #24292e;
border-radius: 6px;
}
.btn-delete:hover{
Expand All @@ -460,3 +462,16 @@ button:focus {
outline: 0;
color: #24292e;
}

.btn-cancel{
padding: 5px 25px;
border: 2px solid rgb(107, 117, 126);
background-color: #eceff1;
color: black;
font-size: 14px;
border-radius: 6px;
}

.btn-cancel:hover{
background-color: rgb(107, 117, 126);
}
80 changes: 80 additions & 0 deletions src/components/Articles/DeleteModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { deleteArticle } from '../../actions/articleActions';

export class DeleteModal extends Component {
constructor(props) {
super(props);
this.state = {
redirect: false,
};
}

componentWillReceiveProps(nextProps) {
if (nextProps.confirmDelete) {
this.setState({
redirect: true,
});
}
}

handleClick = event => {
event.preventDefault();
const { slug, deleteArticle } = this.props;
deleteArticle(slug);
};

render() {
const { redirect } = this.state;
if (redirect) {
const to = { pathname: '/dashboard' };
return (
<Redirect to={to} />
);
}
return (
<div className="modal fade" id="exampleModal" tabIndex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title" id="exampleModalLabel">Confirm Delete</h5>
<button type="button" className="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div className="modal-body">
Are you sure you want to delete this article?
</div>
<div className="modal-footer">
<button type="button" className="btn-cancel" data-dismiss="modal">Cancel</button>
<button type="button" className="btn-delete" onClick={this.handleClick} data-dismiss="modal">Yes, delete</button>
</div>
</div>
</div>
</div>
);
}
}

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

const matchDispatchToProps = dispatch => bindActionCreators({
deleteArticle,
}, dispatch);

DeleteModal.propTypes = {
confirmDelete: PropTypes.bool.isRequired,
deleteArticle: PropTypes.func.isRequired,
slug: PropTypes.string.isRequired,

};

export default connect(
mapStateToProps,
matchDispatchToProps,
)(DeleteModal);
8 changes: 6 additions & 2 deletions src/components/Articles/ReadArticle.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import user from '../../assets/images/user.png';
import DeleteModal from './DeleteModal';

const articleCreated = articleDate => {
const dateTime = new Date(articleDate);
Expand All @@ -16,7 +17,7 @@ const getAuthor = author => {
return 'btn-no-display';
};

const ReadArticle = ({ article }) => (
const ReadArticle = ({ article, slug }) => (
<div className="container view-article">
<div className="row">
<div className="col-1">
Expand Down Expand Up @@ -52,7 +53,10 @@ const ReadArticle = ({ article }) => (
<div className="col-5">
<div id="buttons" className={getAuthor(article.author.username)}>
<input type="button" value="Edit" className="btn-edit" />
<input type="button" value="Delete" className="btn-delete" />
<input type="button" value="Delete" className="btn-delete" data-toggle="modal" data-target="#exampleModal" />
</div>
<div>
<DeleteModal id="exampleModal" slug={slug} />
</div>
</div>
</div>
Expand Down
24 changes: 11 additions & 13 deletions src/components/Articles/SingleArticle.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,17 @@ const SingleArticle = ({ article }) => {
</div>
</div>
</div>
<div className="row">
<div className="col-md-3 article-time">
<p>
<span>{articleCreated(article.createdAt)}</span>
|
<span>{article.reading_time}</span>
</p>
</div>
<div className="row">
<div className="col-sm-8">
<i className="fas fa-tags" />
</div>
</div>
</div>
<div className="row">
<div className="col-md-6 article-time">
<p>
<span>{articleCreated(article.createdAt)}</span>
|
<span>{article.reading_time}</span>
</p>
</div>
<div className="col-sm-4">
<i className="fas fa-tags" />
</div>
</div>
</div>
Expand Down
8 changes: 6 additions & 2 deletions src/components/Articles/ViewArticle.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ export class ViewArticle extends Component {
}

render() {
const { articlePayload, articlePayload: { article } } = this.props;
const {
articlePayload,
articlePayload: { article },
match: { params: { slug } },
} = this.props;

return (
<div>
{Object.keys(articlePayload).length > 0
&& <ReadArticle article={article} />
&& <ReadArticle article={article} slug={slug} />
}
</div>
);
Expand Down
9 changes: 9 additions & 0 deletions src/reducers/articlesReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
GET_ALL_ARTICLES_INITIATED,
LIKE_DISLIKE_ERROR,
LIKE_DISLIKE_SUCCESS,
DELETE_ARTICLE_SUCCESS,
} from '../actions/types';

const initialState = {
Expand All @@ -24,6 +25,7 @@ const initialState = {
articlePayload: {},
likeDislikeSuccess: false,
likeDislikeError: {},
confirmDelete: false,
};

export const articlesReducer = (state = initialState, action) => {
Expand Down Expand Up @@ -72,6 +74,7 @@ export const articlesReducer = (state = initialState, action) => {
return {
...state,
articlePayload: action.payload,
loading: false,
};
case GET_USER_ARTICLES_SUCCESS:
return {
Expand All @@ -93,6 +96,12 @@ export const articlesReducer = (state = initialState, action) => {
...state,
likeDislikeError: action.payload,
};
case DELETE_ARTICLE_SUCCESS:
return {
...state,
loading: false,
confirmDelete: action.payload,
};
default:
return state;
}
Expand Down
Loading

0 comments on commit ecc3984

Please sign in to comment.