mirror of
https://github.com/wgh136/nysoure.git
synced 2025-09-27 12:17:24 +00:00
Add delete comment functionality with confirmation dialog.
This commit is contained in:
@@ -131,6 +131,12 @@ export const i18nData = {
|
||||
"Are you sure you want to delete the file":
|
||||
"Are you sure you want to delete the file",
|
||||
|
||||
// 评论删除相关
|
||||
"Delete Comment": "Delete Comment",
|
||||
"Are you sure you want to delete this comment? This action cannot be undone.":
|
||||
"Are you sure you want to delete this comment? This action cannot be undone.",
|
||||
"Comment deleted successfully": "Comment deleted successfully",
|
||||
|
||||
// New translations
|
||||
"Change Avatar": "Change Avatar",
|
||||
"Change Username": "Change Username",
|
||||
@@ -344,6 +350,11 @@ export const i18nData = {
|
||||
"Delete File": "删除文件",
|
||||
"Are you sure you want to delete the file": "您确定要删除此文件吗",
|
||||
|
||||
"Delete Comment": "删除评论",
|
||||
"Are you sure you want to delete this comment? This action cannot be undone.":
|
||||
"您确定要删除此评论吗?此操作不可撤销。",
|
||||
"Comment deleted successfully": "评论删除成功",
|
||||
|
||||
// New translations
|
||||
"Change Avatar": "更改头像",
|
||||
"Change Username": "更改用户名",
|
||||
@@ -556,6 +567,11 @@ export const i18nData = {
|
||||
"Delete File": "刪除檔案",
|
||||
"Are you sure you want to delete the file": "您確定要刪除此檔案嗎",
|
||||
|
||||
"Delete Comment": "刪除評論",
|
||||
"Are you sure you want to delete this comment? This action cannot be undone.":
|
||||
"您確定要刪除此評論嗎?此操作不可撤銷。",
|
||||
"Comment deleted successfully": "評論刪除成功",
|
||||
|
||||
// New translations
|
||||
"Change Avatar": "更改頭像",
|
||||
"Change Username": "更改用戶名",
|
||||
|
@@ -986,6 +986,18 @@ class Network {
|
||||
}
|
||||
}
|
||||
|
||||
async deleteComment(commentID: number): Promise<Response<void>> {
|
||||
try {
|
||||
const response = await axios.delete(
|
||||
`${this.apiBaseUrl}/comments/${commentID}`,
|
||||
);
|
||||
return response.data;
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
return { success: false, message: e.toString() };
|
||||
}
|
||||
}
|
||||
|
||||
async getServerConfig(): Promise<Response<ServerConfig>> {
|
||||
try {
|
||||
const response = await axios.get(`${this.apiBaseUrl}/config`);
|
||||
|
@@ -1311,6 +1311,7 @@ function CommentTile({ comment }: { comment: Comment }) {
|
||||
</div>
|
||||
{app.user?.id === comment.user.id && (
|
||||
<div className={"flex flex-row-reverse"}>
|
||||
<DeleteCommentDialog commentId={comment.id} />
|
||||
<EditCommentDialog comment={comment} />
|
||||
</div>
|
||||
)}
|
||||
@@ -1457,3 +1458,61 @@ function EditCommentDialog({
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// 新增:删除评论弹窗组件
|
||||
function DeleteCommentDialog({ commentId }: { commentId: number }) {
|
||||
const [isLoading, setLoading] = useState(false);
|
||||
const reload = useContext(context);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const id = `delete_comment_dialog_${commentId}`;
|
||||
|
||||
const handleDelete = async () => {
|
||||
if (isLoading) return;
|
||||
setLoading(true);
|
||||
const res = await network.deleteComment(commentId);
|
||||
const dialog = document.getElementById(id) as HTMLDialogElement;
|
||||
dialog.close();
|
||||
if (res.success) {
|
||||
showToast({ message: t("Comment deleted successfully"), type: "success" });
|
||||
reload();
|
||||
} else {
|
||||
showToast({ message: res.message, type: "error" });
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className={"btn btn-error btn-sm btn-ghost ml-1"}
|
||||
onClick={() => {
|
||||
const dialog = document.getElementById(id) as HTMLDialogElement;
|
||||
dialog.showModal();
|
||||
}}
|
||||
>
|
||||
<MdOutlineDelete size={16} className={"inline-block"} />
|
||||
{t("Delete")}
|
||||
</button>
|
||||
<dialog id={id} className="modal">
|
||||
<div className="modal-box">
|
||||
<h3 className="font-bold text-lg">{t("Delete Comment")}</h3>
|
||||
<p className="py-4">
|
||||
{t("Are you sure you want to delete this comment? This action cannot be undone.")}
|
||||
</p>
|
||||
<div className="modal-action">
|
||||
<form method="dialog">
|
||||
<button className="btn btn-ghost">{t("Close")}</button>
|
||||
</form>
|
||||
<button className="btn btn-error" onClick={handleDelete}>
|
||||
{isLoading ? (
|
||||
<span className={"loading loading-spinner loading-sm"}></span>
|
||||
) : null}
|
||||
{t("Delete")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ func AddCommentRoutes(router fiber.Router) {
|
||||
api.Get("/:resourceID", listComments)
|
||||
api.Get("/user/:username", listCommentsWithUser)
|
||||
api.Put("/:commentID", updateComment)
|
||||
api.Delete("/:commentID", deleteComment)
|
||||
}
|
||||
|
||||
func createComment(c fiber.Ctx) error {
|
||||
@@ -115,3 +116,23 @@ func updateComment(c fiber.Ctx) error {
|
||||
Message: "Comment updated successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func deleteComment(c fiber.Ctx) error {
|
||||
userID, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewRequestError("You must be logged in to delete comment")
|
||||
}
|
||||
commentIDStr := c.Params("commentID")
|
||||
commentID, err := strconv.Atoi(commentIDStr)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid comment ID")
|
||||
}
|
||||
err = service.DeleteComment(uint(commentID), userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: true,
|
||||
Message: "Comment deleted successfully",
|
||||
})
|
||||
}
|
||||
|
@@ -83,3 +83,25 @@ func UpdateCommentContent(commentID uint, content string) (*model.Comment, error
|
||||
db.Preload("User").First(&comment, commentID)
|
||||
return &comment, nil
|
||||
}
|
||||
|
||||
func DeleteCommentByID(commentID uint) error {
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
var comment model.Comment
|
||||
if err := tx.First(&comment, commentID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Delete(&comment).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Model(&model.User{}).Where("id = ?", comment.UserID).Update("comments_count", gorm.Expr("comments_count - 1")).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.
|
||||
Where("type = ? and ref_id = ?", model.ActivityTypeNewComment, commentID).
|
||||
Delete(&model.Activity{}).
|
||||
Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
@@ -84,3 +84,17 @@ func UpdateComment(commentID, userID uint, content string) (*model.CommentView,
|
||||
}
|
||||
return updated.ToView(), nil
|
||||
}
|
||||
|
||||
func DeleteComment(commentID, userID uint) error {
|
||||
comment, err := dao.GetCommentByID(commentID)
|
||||
if err != nil {
|
||||
return model.NewNotFoundError("Comment not found")
|
||||
}
|
||||
if comment.UserID != userID {
|
||||
return model.NewRequestError("You can only delete your own comments")
|
||||
}
|
||||
if err := dao.DeleteCommentByID(commentID); err != nil {
|
||||
return model.NewInternalServerError("Error deleting comment")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user