Skip to content

Commit

Permalink
Merge pull request #49 from andela/ft-edit-comment-history-166816082
Browse files Browse the repository at this point in the history
#166816082 Implement edit comment and view comment edit history functionality
  • Loading branch information
devPinheiro committed Sep 6, 2019
2 parents 6a57524 + 7c92c4b commit e980300
Show file tree
Hide file tree
Showing 18 changed files with 691 additions and 70 deletions.
6 changes: 6 additions & 0 deletions src/actionTypes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,9 @@ export const REQUEST_PASSWORD_RESET = 'REQUEST_PASSWORD_RESET';

export const GET_NOTIFICATION_SUCCESS = 'GET_NOTIFICATION_SUCCESS';
export const GET_NOTIFICATION_START = 'GET_NOTIFICATION_START';
export const UPDATE_COMMENT_START = 'UPDATE_COMMENT_START';
export const UPDATE_COMMENT = 'UPDATE_COMMENT';
export const UPDATE_COMMENT_FAIL = 'UPDATE_COMMENT_FAIL';
export const GET_COMMENT_EDIT_HISTORY_START = 'GET_COMMENT_EDIT_HISTORY_START';
export const GET_COMMENT_EDIT_HISTORY = 'GET_COMMENT_EDIT_HISTORY';
export const CLEAN_UP_COMMENT_EDIT_HISTORY = 'CLEAN_UP_COMMENT_EDIT_HISTORY';
8 changes: 7 additions & 1 deletion src/components/CreateComment/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ export class CreateComment extends Component {
{...comment}
datePublished={datePublished}
handleLike={this.handleLike}
handleCommentModalOpen={this.props.handleCommentModalOpen}
handleCommentModalClose={this.props.handleCommentModalClose}
token={this.props.auth.user.token}
viewerEmail={this.props.auth.user.email}
/>
);
});
Expand Down Expand Up @@ -119,7 +123,9 @@ CreateComment.propTypes = {
token: PropTypes.string,
slugtoken: PropTypes.string,
allComment: PropTypes.object,
auth: PropTypes.object
auth: PropTypes.object,
handleCommentModalOpen: PropTypes.func,
handleCommentModalClose: PropTypes.func
};

export const mapStateToProps = state => {
Expand Down
27 changes: 27 additions & 0 deletions src/components/EditCommentHistory/editCommentHistory.action.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import axiosUtil from '../../utils/axiosConfig';
import * as actionTypes from '../../actionTypes/index';

export const getCommentEditHistory = payload => {
return { type: actionTypes.GET_COMMENT_EDIT_HISTORY, payload };
};

export const getCommentEditHistoryStart = () => {
return { type: actionTypes.GET_COMMENT_EDIT_HISTORY_START };
};

export const cleanUpEditHistory = () => {
return { type: actionTypes.CLEAN_UP_COMMENT_EDIT_HISTORY };
};
export const getEditHistoryRequest = (slug, commentId, token) => {
return async dispatch => {
dispatch(cleanUpEditHistory());
dispatch(getCommentEditHistoryStart());
const response = await axiosUtil.get(
`articles/${slug}/comments/${commentId}/history`,
{
headers: { Authorization: `Bearer ${token}` }
}
);
dispatch(getCommentEditHistory(response.data.data));
};
};
25 changes: 25 additions & 0 deletions src/components/EditCommentHistory/editCommentHistory.reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as types from '../../actionTypes';

const commentEditHistoryReducer = (state = {}, action) => {
switch (action.type) {
case types.GET_COMMENT_EDIT_HISTORY_START:
return {
...state,
isLoading: true
};
case types.GET_COMMENT_EDIT_HISTORY:
return {
...state,
history: action.payload,
isLoading: false
};
case types.CLEAN_UP_COMMENT_EDIT_HISTORY:
return {
...state,
isLoading: false
};
default:
return state;
}
};
export default commentEditHistoryReducer;
136 changes: 136 additions & 0 deletions src/components/EditCommentHistory/editCommentHistory.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import React from 'react';
import '@babel/polyfill';
import mockAxios from 'axios';
import { shallow } from 'enzyme';
import editCommentHistoryReducer from './editCommentHistory.reducer';
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { getEditHistoryRequest } from './editCommentHistory.action';
import { EditCommentHistory } from './index.jsx';
import {
GET_COMMENT_EDIT_HISTORY,
GET_COMMENT_EDIT_HISTORY_START,
CLEAN_UP_COMMENT_EDIT_HISTORY
} from '../../actionTypes/index';
import Loader from '../LoadingIndicator/index.jsx';

const middlewares = [thunk];
const mockStore = configureStore(middlewares);

const slug = 'How-To-Become-a-10x-Engineer';
const comment = 'Some new comment';
const token = 'jndmfdfdfdfkldk';
const response = {
'6:00pm, 12th August 2030': 'previous comment',
'6:01pm, 12th August 2030': 'another comment',
'6:03pm, 12th August 2030': 'another comment'
};

describe('Edit comment History actions tests', () => {
let store;
beforeEach(() => {
store = mockStore({});
jest.resetAllMocks();
});
afterEach(() => {
store.clearActions();
});

it('Should dispatch The UPDATE_COMMENT action', async () => {
const mockData = {
data: {
data: {
response
}
}
};

mockAxios.get.mockResolvedValue({
data: mockData.data
});

const expectedActions = [
{ type: 'CLEAN_UP_COMMENT_EDIT_HISTORY' },
{ type: 'GET_COMMENT_EDIT_HISTORY_START' },
{
type: 'GET_COMMENT_EDIT_HISTORY',
payload: {
response
}
}
];

await store.dispatch(getEditHistoryRequest(slug, comment, token));
expect(store.getActions()).toEqual(expectedActions);
});
});

describe('Get Comment Edit History Reducer Tests', () => {
const initialState = {};
it('Should return a new state if it recieves a GET_COMMENT_EDIT_HISTORY_START action type', () => {
const newState = editCommentHistoryReducer(initialState, {
type: GET_COMMENT_EDIT_HISTORY_START,
payload: {}
});
expect(newState).toEqual({
isLoading: true
});
});

it('Should return a new state if it recieves a GET_COMMENT_EDIT_HISTORY action type', () => {
const newState = editCommentHistoryReducer(initialState, {
type: GET_COMMENT_EDIT_HISTORY,
payload: response
});
expect(newState).toEqual({
isLoading: false,
history: response
});
});

it('Should return a new state if it recieves a CLEAN_UP_COMMENT_EDIT_HISTORY action type', () => {
const newState = editCommentHistoryReducer(initialState, {
type: CLEAN_UP_COMMENT_EDIT_HISTORY,
payload: {}
});
expect(newState).toEqual({
isLoading: false
});
});
});

describe('EditCommentHistory Template', () => {
it(`should render the EditCommentHistory Template when there is no edit history`, () => {
const props = {
commentHistory: {
history: {
commentEditHistory: {}
}
},
isLoading: false
};
const component = shallow(<EditCommentHistory {...props} />);
expect(
component
.find('.comment-edit-history')
.contains(
<h5 className="pt-5 text-center">This comment has no edit history</h5>
)
).toBeTruthy();
});

it(`should render the EditCommentHistory Template when the request is loading`, () => {
const props = {
commentHistory: {
history: {
commentEditHistory: { response }
}
},
isLoading: true
};
const component = shallow(<EditCommentHistory {...props} />);
expect(
component.find('.comment-edit-history').contains(<Loader />)
).toBeTruthy();
});
});
48 changes: 48 additions & 0 deletions src/components/EditCommentHistory/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import './style.scss';
import Loader from '../LoadingIndicator/index.jsx';

export class EditCommentHistory extends Component {
render() {
const { commentHistory, isLoading, lightTheme } = this.props;
const additionalClass = lightTheme ? 'comment-body-light' : '';
const historyList = isLoading ? (
<Loader />
) : commentHistory &&
commentHistory.history &&
Object.keys(commentHistory.history.commentEditHistory).length > 1 ? (
Object.entries(commentHistory.history.commentEditHistory).map(
(comment, i) => {
return (
<div key={i} className={`comment-body ${additionalClass}`}>
<span className={'w-100 d-block p-2'}>{comment[1]}</span>
<span className={'w-100 d-block time-stamp text-right p-1'}>
{moment(comment[0]).format('MMMM Do, YYYY, h:mm:ss a')}
</span>
</div>
);
}
)
) : (
<h5 className="pt-5 text-center">This comment has no edit history</h5>
);
return (
<>
<div className="comment-edit-history">{historyList}</div>
</>
);
}
}

EditCommentHistory.propTypes = {
lightTheme: PropTypes.bool,
commentHistory: PropTypes.object,
slug: PropTypes.string,
token: PropTypes.string,
commentId: PropTypes.any,
isLoading: PropTypes.bool
};

export default EditCommentHistory;
32 changes: 32 additions & 0 deletions src/components/EditCommentHistory/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.comment-edit-history {
height: 300px;
width: 50vw;
overflow: scroll;
}
.time-stamp {
background-color: rgba(0, 0, 0, 0.64);
border-top: 1px solid rgba(0, 0, 0, 0.125);
font-size: 0.5em;
}
.comment-body {
background: #161616;
border: 1px solid grey;
border-radius: 3px;
color: inherit;
min-height: 2em;
margin-bottom: 7px;
}
.edit-functionality:hover {
cursor: pointer;
}
.modal-main {
top: 35% !important;
}

.comment-body-light {
background: white !important;
color: black !important;
.time-stamp {
background: rgba(0, 0, 0, 0.03) !important;
}
}
22 changes: 22 additions & 0 deletions src/components/Editcomment/editComment.action.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import axiosUtil from '../../utils/axiosConfig';
import * as actionTypes from '../../actionTypes/index';

export const updateComment = payload => {
return {
type: actionTypes.UPDATE_COMMENT,
payload: { payload, isEdited: true }
};
};

export const updateCommentRequest = (slug, commentId, comment, token) => {
return async dispatch => {
const response = await axiosUtil.patch(
`articles/${slug}/comments/${commentId}/edit`,
{ comment },
{
headers: { Authorization: `Bearer ${token}` }
}
);
dispatch(updateComment(response.data.data));
};
};
Loading

0 comments on commit e980300

Please sign in to comment.