Created
February 25, 2023 09:44
-
-
Save florianwalther-private/7811f6639abd6178bde9a2fba3da4116 to your computer and use it in GitHub Desktop.
Question about organizing code into JSX variables
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UserProfileLink from "@/components/UserProfileLink"; | |
import { formatRelativeDate } from "@/helpers/utils"; | |
import { useAuthenticatedUser } from "@/hooks/useAuthenticatedUser"; | |
import { Comment as CommentModel } from "@/models/comment"; | |
import { NotFoundError } from "@/network/http-errors"; | |
import { AppContext } from "@/pages/_app"; | |
import { useContext, useState } from "react"; | |
import { Button } from "react-bootstrap"; | |
import CreateCommentBox from "./CreateCommentBox"; | |
import EditCommentBox from "./EditCommentBox"; | |
import * as BlogApi from "@/network/api/blog"; | |
interface CommentProps { | |
comment: CommentModel, | |
onReplyCreated: (reply: CommentModel) => void, | |
onCommentUpdated: (updatedComment: CommentModel) => void, | |
onCommentDeleted: () => void, | |
} | |
const Comment = ({ comment, onReplyCreated, onCommentUpdated, onCommentDeleted }: CommentProps) => { | |
const { user } = useAuthenticatedUser(); | |
const appContext = useContext(AppContext); | |
const [showEditBox, setShowEditBox] = useState(false); | |
const [showReplyBox, setShowReplyBox] = useState(false); | |
const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false); | |
const [deleteInProgress, setDeleteInProgress] = useState(false); | |
async function deleteComment() { | |
try { | |
setDeleteInProgress(true); | |
await BlogApi.deleteComment(comment._id); | |
onCommentDeleted(); | |
} catch (error) { | |
console.error(error); | |
if (error instanceof NotFoundError) { | |
onCommentDeleted(); | |
} else { | |
alert(error); | |
} | |
} finally { | |
setDeleteInProgress(false); | |
} | |
} | |
const commentLayout = | |
<CommentLayout | |
comment={comment} | |
onReplyClicked={() => { | |
if (user) { | |
setShowReplyBox(true); | |
} else { | |
appContext.showLoginModal(); | |
} | |
}} | |
onEditClicked={() => { | |
setShowEditBox(true); | |
setShowDeleteConfirmation(false); | |
}} | |
onDeleteClicked={() => setShowDeleteConfirmation(true)} | |
/> | |
const editCommentBox = | |
<EditCommentBox | |
comment={comment} | |
onCommentUpdated={(updatedComment) => { | |
onCommentUpdated(updatedComment); | |
setShowEditBox(false); | |
}} | |
onCancel={() => setShowEditBox(false)} | |
/> | |
const replyBox = | |
<CreateCommentBox | |
blogPostId={comment.blogPostId} | |
title="Write a reply" | |
defaultText={comment.parentCommentId ? `@${comment.author.username} ` : ""} | |
onCommentCreated={(newReply) => { | |
onReplyCreated(newReply); | |
setShowReplyBox(false); | |
}} | |
parentCommentId={comment.parentCommentId || comment._id} | |
onCancel={() => setShowReplyBox(false)} | |
showCancel | |
/> | |
const deleteConfirmationSection = | |
<div> | |
<p className="text-danger">Do you really want to delete this comment?</p> | |
<Button | |
variant="danger" | |
className="me-2" | |
onClick={deleteComment} | |
disabled={deleteInProgress}> | |
Delete | |
</Button> | |
<Button | |
variant="outline-danger" | |
onClick={() => setShowDeleteConfirmation(false)}> | |
Cancel | |
</Button> | |
</div> | |
return ( | |
<div className="w-100"> | |
<hr /> | |
{showEditBox ? editCommentBox : commentLayout} | |
{showDeleteConfirmation && deleteConfirmationSection} | |
{showReplyBox && replyBox} | |
</div> | |
); | |
} | |
export default Comment; | |
interface CommentLayoutProps { | |
comment: CommentModel, | |
onReplyClicked: () => void, | |
onEditClicked: () => void, | |
onDeleteClicked: () => void, | |
} | |
const CommentLayout = ({ comment, onReplyClicked, onEditClicked, onDeleteClicked }: CommentLayoutProps) => { | |
const { user } = useAuthenticatedUser(); | |
return ( | |
<div> | |
<div className="mb-2">{comment.text}</div> | |
<div className="d-flex gap-2 align-items-center"> | |
<UserProfileLink user={comment.author} /> | |
{formatRelativeDate(comment.createdAt)} | |
{comment.updatedAt > comment.createdAt && <span>(Edited)</span>} | |
</div> | |
<div className="mt-1 d-flex gap-2"> | |
<Button | |
variant="link" | |
onClick={onReplyClicked}> | |
<small>Reply</small> | |
</Button> | |
{user?._id === comment.author._id && | |
<> | |
<Button | |
variant="link" | |
onClick={onEditClicked}> | |
<small>Edit</small> | |
</Button> | |
<Button | |
variant="link" | |
onClick={onDeleteClicked}> | |
<small>Delete</small> | |
</Button> | |
</> | |
} | |
</div> | |
</div> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment