added deleted comment indicator

This commit is contained in:
2025-03-22 17:48:05 +01:00
parent 4a67f1f94b
commit b2cd0fc560
10 changed files with 46 additions and 155 deletions
+9 -11
View File
@@ -15,7 +15,6 @@ import {
} from "@/components/ui/form";
import { commentSchema } from "@/lib/validation/zod/comment";
import CommentEditor from "../editor/comment-editor";
import { createComment } from "@/server/actions/comment";
import { toast } from "sonner";
import { EditorInstance } from "novel";
import { XIcon } from "lucide-react";
@@ -39,8 +38,15 @@ function CommentForm({
onSuccess: (comment) => {
setLoading(false);
socket?.emit(ADD_COMMENT_EVENT, comment);
toast.success("Kommentar hinzugefügt.");
setTimeout(() => {
const el = commentRefs.current.get(comment?.id!);
el?.scrollIntoView({
behavior: "smooth",
block: "start",
});
el?.classList.add("animate-fade-in");
}, 500);
},
onError: () => {
setLoading(false);
@@ -65,15 +71,6 @@ function CommentForm({
form.reset();
editor?.commands?.clearContent();
removeReplyComment();
// setTimeout(() => {
// const el = commentRefs.current.get(res?.data?.data!);
// console.log("el", el);
// el?.scrollIntoView({
// behavior: "smooth",
// block: "start",
// });
// el?.classList.add("animate-fade-in");
// }, 500);
}
React.useEffect(() => {
@@ -116,6 +113,7 @@ function CommentForm({
type="submit"
className="ml-auto h-max py-1"
size="sm"
disabled={loading || !form.formState.isDirty}
>
Absenden
</Button>
+2 -2
View File
@@ -4,7 +4,7 @@ import { buildCommentTree } from "@/lib/utils/comments";
import Comment from "./comment";
import { useSession } from "../session-provider";
function CommentList({
export const CommentList = React.memo(function ({
comments,
setReplyComment,
commentRefs,
@@ -29,5 +29,5 @@ function CommentList({
))}
</ul>
);
}
});
export default CommentList;
+15 -43
View File
@@ -19,32 +19,22 @@ const Comment = React.memo(
level?: number;
}) => {
const { comment, setReplyComment, setRef, session, level = 0 } = props;
const isAuthor = session?.user?.id === comment.author?.id;
const isAuthor = session?.user?.id === comment?.author?.id;
return (
// <div className="">
// </div>
// <div className="comment-replies" style={{ marginLeft: "20px" }}>
// {comment.children.map((child) => (
// <Comment
// key={child.id}
// comment={child}
// setReplyComment={setReplyComment}
// setRef={(el) => setRef(el)} // Ensure this is stable
// session={session}
// level={level + 1}
// />
// ))}
// </div>
// </div>
<div
className={cn(
level > 0 && "ml-4 border-l",
comment.children.length && "border-l",
comment?.children?.length && "border-l",
comment?.missingParent && "border-l",
)}
>
{comment.missingParent && (
<div className="p-4 pt-0 text-sm italic text-muted-foreground">
Antwort auf: Kommentar wurde gelöscht
</div>
)}
<div
className="flex items-start gap-2 pl-2 hover:bg-muted"
ref={setRef}
@@ -57,7 +47,7 @@ const Comment = React.memo(
<div className="w-full">
<div className="flex w-full items-center gap-2">
<h5 className="text-lg font-medium capitalize">
{comment.author?.name} {level}
{comment.author?.name}
</h5>
{isAuthor && (
<Badge variant={"outline"} className="text-xs">
@@ -85,39 +75,21 @@ const Comment = React.memo(
</div>
</div>
</div>
{comment.children && comment.children.length > 0 && (
{comment?.children && comment.children.length > 0 && (
<div className="pl-4">
{comment.children.map((child) => (
{comment.children.map((child, idx) => (
<Comment
key={child.id}
key={child?.id ?? idx}
{...props}
comment={child}
comment={child as CommentNode}
level={level + 1}
/>
))}
</div>
)}
</div>
// <div className={`flex ${level > 0 ? "ml-4" : ""} w-full`}>
// <div
// className={`${comment.children?.length || level > 0 ? "border-l" : ""} w-full pl-2`}
// >
// {comment.children && comment.children.length > 0 && (
// <div className="pl-4">
// {comment.children.map((child) => (
// <Comment
// key={child.id}
// {...props}
// comment={child}
// level={level + 1}
// />
// ))}
// </div>
// )}
// </div>
// </div>
);
},
);
export default Comment;
+9 -5
View File
@@ -9,28 +9,32 @@ export function buildCommentTree(comments: Comment[]): Array<CommentNode> {
commentMap[comment.id] = {
...comment,
children: [],
missingParent: false,
};
});
// Second pass: Build the tree by connecting children to parents
const rootComments: CommentNode[] = [];
const rootComments: Array<CommentNode> = [];
comments.forEach((comment) => {
const node = commentMap[comment.id];
const node = commentMap[comment.id]!;
// If parentId is null or empty string, it's a root comment
if (!comment.parentId) {
rootComments.push(node!);
rootComments.push(node);
} else {
// Add as a child to its parent if parent exists
const parent = commentMap[comment.parentId];
if (parent) {
parent.children.push(node!);
// Add as a child to its parent if parent exists
parent.children.push(node);
} else {
// Parent doesn't exist, treat as root comment
// Mark that the parent is missing
node.missingParent = true;
rootComments.push(node!);
}
}
});
return rootComments;
}
-48
View File
@@ -1,48 +0,0 @@
"use server";
import { appRoutes } from "@/config";
import { commentSchema } from "@/lib/validation/zod/comment";
import { api } from "@/trpc/server";
import { revalidatePath } from "next/cache";
import { z } from "zod";
import { actionClient } from ".";
export const createComment = actionClient
.schema(
z.object({
comment: commentSchema,
articleId: z.string(),
}),
)
.action(async ({ parsedInput: { comment, articleId } }) => {
const commentId = await api.comment.create({
comment,
articleId,
});
if (!commentId)
return {
failure: "Incorrect credentials",
};
revalidatePath(appRoutes.article(articleId));
return {
data: commentId,
success: true,
};
});
export async function deleteComment(commentId: string) {
const articleId = (
await api.comment.delete({
commentId,
})
)?.articleId;
if (!articleId)
return {
success: false,
message: "Error deleting comment",
};
revalidatePath(appRoutes.article(articleId));
return {
success: true,
};
}
-3
View File
@@ -1,3 +0,0 @@
import { createSafeActionClient } from "next-safe-action";
export const actionClient = createSafeActionClient();
+2 -1
View File
@@ -60,7 +60,8 @@ export type Comment = typeof comments.$inferSelect & {
};
export type CommentNode = Comment & {
children: CommentNode[];
children: Array<CommentNode | DeletedNode>;
missingParent: boolean;
};
export const commentVotes = createTable(
+1 -1
View File
@@ -19,7 +19,7 @@ const createSocketServer = () => {
if (!global.io) {
global.io = new Server(server, {
cors: {
origin,
origin: "*",
methods: ["GET", "POST"],
},
});