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":
|
||||||
"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
|
// New translations
|
||||||
"Change Avatar": "Change Avatar",
|
"Change Avatar": "Change Avatar",
|
||||||
"Change Username": "Change Username",
|
"Change Username": "Change Username",
|
||||||
@@ -344,6 +350,11 @@ export const i18nData = {
|
|||||||
"Delete File": "删除文件",
|
"Delete File": "删除文件",
|
||||||
"Are you sure you want to delete the 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
|
// New translations
|
||||||
"Change Avatar": "更改头像",
|
"Change Avatar": "更改头像",
|
||||||
"Change Username": "更改用户名",
|
"Change Username": "更改用户名",
|
||||||
@@ -556,6 +567,11 @@ export const i18nData = {
|
|||||||
"Delete File": "刪除檔案",
|
"Delete File": "刪除檔案",
|
||||||
"Are you sure you want to delete the 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
|
// New translations
|
||||||
"Change Avatar": "更改頭像",
|
"Change Avatar": "更改頭像",
|
||||||
"Change Username": "更改用戶名",
|
"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>> {
|
async getServerConfig(): Promise<Response<ServerConfig>> {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${this.apiBaseUrl}/config`);
|
const response = await axios.get(`${this.apiBaseUrl}/config`);
|
||||||
|
@@ -1311,6 +1311,7 @@ function CommentTile({ comment }: { comment: Comment }) {
|
|||||||
</div>
|
</div>
|
||||||
{app.user?.id === comment.user.id && (
|
{app.user?.id === comment.user.id && (
|
||||||
<div className={"flex flex-row-reverse"}>
|
<div className={"flex flex-row-reverse"}>
|
||||||
|
<DeleteCommentDialog commentId={comment.id} />
|
||||||
<EditCommentDialog comment={comment} />
|
<EditCommentDialog comment={comment} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -1456,4 +1457,62 @@ function EditCommentDialog({
|
|||||||
</dialog>
|
</dialog>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增:删除评论弹窗组件
|
||||||
|
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("/:resourceID", listComments)
|
||||||
api.Get("/user/:username", listCommentsWithUser)
|
api.Get("/user/:username", listCommentsWithUser)
|
||||||
api.Put("/:commentID", updateComment)
|
api.Put("/:commentID", updateComment)
|
||||||
|
api.Delete("/:commentID", deleteComment)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createComment(c fiber.Ctx) error {
|
func createComment(c fiber.Ctx) error {
|
||||||
@@ -115,3 +116,23 @@ func updateComment(c fiber.Ctx) error {
|
|||||||
Message: "Comment updated successfully",
|
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)
|
db.Preload("User").First(&comment, commentID)
|
||||||
return &comment, nil
|
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
|
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