app/javascript/components/CommentsContainer.js
import React, { useReducer, useState } from "react";
import PropTypes from "prop-types";
import { UserContext } from "./user-context";
import { reducer } from "./reducers";
import CommentForm from "./CommentForm";
import CommentsHeader from "./CommentsHeader";
import CommentsList from "./CommentsList"
const CommentsContainer = ({
initialCommentFormsVisibility,
initialComments,
initialTextAreaValues,
nodeId
}) => {
const initialState = {
comments: initialComments,
commentFormsVisibility: initialCommentFormsVisibility,
textAreaValues: initialTextAreaValues
}
const [state, dispatch] = useReducer(reducer, initialState);
// React Hook: <textarea> Input State for Comment Forms
// ie. the value that shows inside a comment form's <textarea>
// main and reply contain empty strings
// edit forms contain the raw comment text to be edited
// const [textAreaValues, setTextAreaValues] = useState(initialTextAreaValues);
// function for handling user input into comment form <textarea>s
const handleTextAreaChange = (event) => {
const value = event.target.value;
const formId = event.target.dataset.formId // eg. "main", "reply-123", "edit-432"
// keep the old state values (as ...state) and insert the new one
// setTextAreaValues(state => ({ ...state, [formId]: value }));
dispatch({
type: "UPDATE TEXTAREA VALUE",
commentFormId: formId,
newValue: value
});
}
// Functions for Creating, Updating, Deleting Comments
const handleCreateComment = (commentId, formType) => {
// form ID is either reply-123 or main
const formId = formType === "reply" ? "reply-" + commentId : "main";
console.log(state.textAreaValues);
const commentBody = state.textAreaValues[formId];
$.post(
"/comment/react/create/" + nodeId,
{
body: commentBody,
id: nodeId,
reply_to: formType === "reply" ? commentId : null
},
function(data) {
notyNotification('mint', 3000, 'success', 'topRight', 'Comment Added!');
const newCommentId = data.comment[0].commentId;
const newCommentRawText = data.comment[0].rawCommentText;
// blank out the value of textarea & also create a value for the new comment's edit form
// setTextAreaValues(oldState => ({ ...oldState, [formId]: "", ["edit-" + newCommentId]: newCommentRawText }));
dispatch({
type: "UPDATE TEXTAREA VALUE",
commentFormId: formId,
newValue: ""
});
dispatch({
type: "CREATE NEW TEXTAREA VALUE",
commentFormId: "edit-" + newCommentId,
newValue: newCommentRawText
});
// the new comment form comes with an edit form, its toggle state needs to be created as well
// TODO: create multicase for "CREATE NEW COMMENT FORM" in reducers.js
dispatch({
type: "CREATE NEW COMMENT FORM VISIBILITY",
commentFormId: "edit-" + newCommentId
})
// if the comment doesn't have a replyTo, then it's a parent comment
// parent comments have reply forms, this needs to be set in state as well.
if (!data.comment[0].replyTo) {
dispatch({
type: "CREATE NEW COMMENT FORM VISIBILITY",
commentFormId: "reply-" + newCommentId
})
}
// call useReducer's dispatch function to push the comment into state
dispatch({
type: "CREATE COMMENT",
newComment: data.comment[0]
})
// close the comment form
if (formType !== "main") {
dispatch({
type: "HIDE COMMENT FORM",
commentFormId: formId
});
}
}
);
}
const handleUpdateComment = (commentId) => {
const formId = "edit-" + commentId;
const commentBody = state.textAreaValues[formId];
$.post(
"/comment/react/update/" + commentId,
{
id: commentId,
body: commentBody
},
function(data) {
// call useReducer's dispatch function to update the comment in state
dispatch({
type: "UPDATE COMMENT",
newComment: data.comment[0]
})
// close the edit comment form
dispatch({
type: "HIDE COMMENT FORM",
commentFormId: formId
});
notyNotification('mint', 3000, 'success', 'topRight', 'Comment Updated!');
}
);
}
const handleDeleteComment = (commentId) => {
$.post(
"/comment/react/delete/" + commentId,
{
id: commentId
},
function(data) {
if (data.success) {
dispatch({
type: "DELETE COMMENT",
commentId
})
notyNotification('sunset', 3000, 'error', 'topRight', 'Comment deleted');
}
}
)
}
return (
<UserContext.Consumer>
{currentUser => (
<div id="legacy-editor-container" className="row">
<div id="comments" className="col-lg-10 comments">
<CommentsHeader comments={state.comments} />
<CommentsList
commentFormsVisibility={state.commentFormsVisibility}
comments={state.comments}
currentUser={currentUser}
dispatch={dispatch}
handleCreateComment={handleCreateComment}
handleDeleteComment={handleDeleteComment}
handleTextAreaChange={handleTextAreaChange}
handleUpdateComment={handleUpdateComment}
textAreaValues={state.textAreaValues}
/>
{/* main comment form */}
{
currentUser ?
<CommentForm
commentFormType="main"
formId="main"
handleFormSubmit={handleCreateComment}
handleTextAreaChange={handleTextAreaChange}
textAreaValue={state.textAreaValues["main"]}
/> :
<p>
<a href="/login">Login</a> to comment.
</p>
}
</div>
</div>
)}
</UserContext.Consumer>
);
}
CommentsContainer.propTypes = {
initialCommentFormsVisibility: PropTypes.objectOf(PropTypes.bool).isRequired,
initialComments: PropTypes.array.isRequired,
initialTextAreaValues: PropTypes.objectOf(PropTypes.string).isRequired,
nodeId: PropTypes.number.isRequired
};
export default CommentsContainer;