Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/conduit/articles/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Comment(Model, SurrogatePK):
comment_id = Column(db.Integer, db.ForeignKey('comment.id'), nullable=True)
parentComment = relationship('Comment', backref=db.backref('parent', remote_side=[id]), lazy='dynamic')


def __init__(self, article, author, body, comment_id=None, **kwargs):
db.Model.__init__(self, author=author, body=body, article=article, **kwargs)

Expand Down
2 changes: 1 addition & 1 deletion components/article/ArticlePreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const ArticlePreview = ({ article }) => {
if (!isLoggedIn) {
Router.push(`/user/login`);
return;
}
}

setPreview({
...preview,
Expand Down
1 change: 1 addition & 0 deletions components/comment/CommentInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { SERVER_BASE_URL } from "../../lib/utils/constant";
import storage from "../../lib/utils/storage";

const CommentInput = () => {

const { data: currentUser } = useSWR("user", storage);
const isLoggedIn = checkLogin(currentUser);
const router = useRouter();
Expand Down
84 changes: 80 additions & 4 deletions components/comment/CommentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import { useRouter } from "next/router";
import React from "react";
import useSWR from "swr";

import { useState } from 'react';
import { message } from 'antd';
import checkLogin from "../../lib/utils/checkLogin";
import storage from "../../lib/utils/storage";
import EditorBox from "./EditorBox";

import CommentInput from "./CommentInput";
import ErrorMessage from "../common/ErrorMessage";
import LoadingSpinner from "../common/LoadingSpinner";
Expand All @@ -11,7 +17,29 @@ import { SERVER_BASE_URL } from "../../lib/utils/constant";
import fetcher from "../../lib/utils/fetcher";
import { Comment, Avatar } from 'antd';


const CommentList = () => {
// clickedComment is the value of the id of the comment that has clicked the Reply To button
var [clickedComment, setClick] = useState( '' );

const { data: currentUser } = useSWR("user", storage);
const isLoggedIn = checkLogin(currentUser)

// After the editor box is submitted, this sets the clickedComment ID back to default (-1)
const setSubmitData = (handleClick) => {
setClick( handleClick );
}

const handleClickReplyTo = (comment) => {

if (isLoggedIn) {
setClick( comment.id );
}
else { // Not Logged In
message.info("Please log in to reply", 10)
}
}

const router = useRouter();
const {
query: { pid },
Expand All @@ -32,13 +60,35 @@ const CommentList = () => {
);

const { comments } = data;


const recurseComments = (comments) => {
return (

return (

comments.map((comment: CommentType) => (

<Comment
key={comment.id}
actions={[<span key="comment-nested-reply-to">Reply to</span>]}
actions= {[
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the comment is made the editor should close

/*
If the clickedComment has this id, then there is the Editor Box, so hide the Reply To
Else, the clickedComment does NOT have this id,
so show the Reply To option
*/

clickedComment == comment.id ?
null
:
<span key="comment-nested-reply-to"
onClick= {() =>
handleClickReplyTo(comment)
}

>Reply to </span>,

]}

author={comment.author.username}
avatar={
<Avatar
Expand All @@ -47,18 +97,44 @@ const CommentList = () => {
/>
}
content={
<p>{comment.body}</p>
<div>
<p>
{ comment.body }
</p>
<p>
{
/*
If the clickedComment has this id, then show the Editor Box
*/
clickedComment == comment.id ?
<EditorBox
commentId = {comment.id}
handleClick = { setSubmitData }
/>
:
null
}
</p>

</div>

}
>
{comment.parentComment.comments.length > 0 ? recurseComments(comment.parentComment.comments) : null}

{
comment.parentComment.comments.length > 0 ? recurseComments(comment.parentComment.comments) : null
}

</Comment>

)))
}

return (
<div>
<CommentInput />
{recurseComments(comments)}

</div>
);
};
Expand Down
93 changes: 93 additions & 0 deletions components/comment/EditorBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Based on CommentInput.tsx

import axios from "axios";
import { useRouter } from "next/router";
import React from "react";
import useSWR, { trigger } from "swr";

import checkLogin from "../../lib/utils/checkLogin";
import { SERVER_BASE_URL } from "../../lib/utils/constant";
import storage from "../../lib/utils/storage";


import { Form, Button, Input} from 'antd';
const { TextArea } = Input;

var clickedSubmit = false;

const Editor = ( { onChange, onSubmit, submitting, value } ) => (
<>
<Form.Item>
<TextArea rows={4} onChange={onChange} value={value} />
</Form.Item>
<Form.Item>
<Button htmlType="submit" loading={submitting} onClick={onSubmit} type="primary">
Add Comment
</Button>
</Form.Item>
</>
)

const EditorBox = ( props ) => {
const { data: currentUser } = useSWR("user", storage);
const isLoggedIn = checkLogin(currentUser);
const router = useRouter();
const {
query: { pid },
} = router;

const [content, setContent] = React.useState("");
const [isLoading, setLoading] = React.useState(false);

clickedSubmit = false;

const handleChange = React.useCallback((e) => {
setContent(e.target.value);
}, []);

const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
await axios.post(
`${SERVER_BASE_URL}/articles/${encodeURIComponent(String(pid))}/comments`,
JSON.stringify({
comment: {
body: content,
comment_id: props.commentId,
},
}),
{
headers: {
"Content-Type": "application/json",
Authorization: `Token ${encodeURIComponent(currentUser?.token)}`,
},
}
);
setLoading(false);
setContent("");
trigger(`${SERVER_BASE_URL}/articles/${pid}/comments`);

// This editor box has been submitted, so set the CommentID to -1 to hide the editor box
props.handleClick("-1");

};

if (!isLoggedIn) {
return (
null
);

} else { // is Logged In
return (
<Editor
onChange={ handleChange }
onSubmit={ handleSubmit }
submitting = { isLoading }
value={ content }
/>
);
}

};

export default EditorBox;
2 changes: 1 addition & 1 deletion lib/types/commentType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ export type Author = {

export type CommentChildren = {
comments: CommentType[];
}
}
3 changes: 3 additions & 0 deletions pages/article/[pid].tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

import marked from "marked";
import Router, { useRouter } from "next/router";
import React from "react";
Expand All @@ -16,6 +17,7 @@ import CommentList from "../../components/comment/CommentList";
import ArticleAPI from "../../lib/api/article";
import { Article } from "../../lib/types/articleType";
import ArticleTags from "../../components/article/ArticleTags";
import { emitKeypressEvents } from "readline";

const ArticleContain = styled.div`
width: 880px;
Expand Down Expand Up @@ -82,6 +84,7 @@ const ArticlePage = (initialArticle) => {
const { data: currentUser } = useSWR("user", storage);
const isLoggedIn = checkLogin(currentUser);


const handleClickFavorite = async slug => {
if (!isLoggedIn) {
Router.push(`/user/login`);
Expand Down