feat(comments): migrate to backend API

This commit is contained in:
zetaloop
2026-03-01 22:40:29 +08:00
parent 505d9c0168
commit 236c1a24da
4 changed files with 169 additions and 69 deletions
+75 -46
View File
@@ -1,56 +1,85 @@
import { addNotification } from "@/lib/api/notifications"
import { allow, deny } from "@/lib/decision"
import { useAuthStore } from "@/store/auth"
import { useCommentStore } from "@/store/comments"
import { usePostStore } from "@/store/posts"
import { toApiError } from "@/lib/errors"
import type { Comment } from "@/lib/types"
export function listComments() {
return useCommentStore.getState().comments
import { httpJson } from "./http"
type Paginated<T> = {
items: T[]
meta: {
total: number
offset: number
limit: number
}
}
export function listCommentsByPost(postId: string) {
return useCommentStore.getState().comments.filter((comment) => comment.postId === postId)
type ListOptions = {
offset?: number
limit?: number
}
export function addComment(postId: string, content: string) {
const user = useAuthStore.getState().user
if (!user) {
return deny(401, "请先登录")
}
const post = usePostStore.getState().posts.find((item) => item.id === postId)
if (!post) {
return deny(404, "帖子不存在")
}
const comment = useCommentStore.getState().addComment(postId, user, content)
if (!comment) {
return deny(400, "评论内容不能为空")
}
usePostStore.getState().incrementCommentCount(postId)
addNotification({
type: "community",
title: "帖子收到新评论",
content: `${post.title}》有新的评论`,
link: `/post/${post.id}`,
function withOffsetLimit(path: string, options?: ListOptions): string {
const offset = options?.offset ?? 0
const limit = options?.limit ?? 1000
const searchParams = new URLSearchParams({
offset: String(offset),
limit: String(limit),
})
return allow()
return `${path}?${searchParams.toString()}`
}
export function toggleCommentLike(commentId: string) {
const user = useAuthStore.getState().user
if (!user) {
return deny(401, "请先登录")
}
const comment = useCommentStore.getState().comments.find((item) => item.id === commentId)
if (!comment) {
return deny(404, "评论不存在")
}
useCommentStore.getState().toggleCommentLike(commentId)
return allow()
export async function listCommentsByPost(
postId: string,
options?: ListOptions,
): Promise<Comment[]> {
const encodedId = encodeURIComponent(postId)
const res = await httpJson<Paginated<Comment>>(
withOffsetLimit(`/api/v1/posts/${encodedId}/comments`, options),
{
cache: "no-store",
},
)
return res.items
}
export async function addComment(postId: string, content: string) {
const encodedId = encodeURIComponent(postId)
try {
await httpJson<unknown>(`/api/v1/posts/${encodedId}/comments`, {
method: "POST",
cache: "no-store",
json: { content },
})
return allow()
} catch (err: unknown) {
if (err instanceof Error && err.message === "UNAUTHORIZED") {
return deny(401, "请先登录")
}
const apiError = toApiError(err)
return deny(apiError.code, apiError.msg)
}
}
export async function toggleCommentLike(commentId: string, currentlyLiked: boolean) {
const encodedId = encodeURIComponent(commentId)
try {
if (currentlyLiked) {
await httpJson<unknown>(`/api/v1/comments/${encodedId}/like`, {
method: "DELETE",
cache: "no-store",
})
} else {
await httpJson<unknown>(`/api/v1/comments/${encodedId}/like`, {
method: "POST",
cache: "no-store",
})
}
return allow()
} catch (err: unknown) {
if (err instanceof Error && err.message === "UNAUTHORIZED") {
return deny(401, "请先登录")
}
const apiError = toApiError(err)
return deny(apiError.code, apiError.msg)
}
}