feat(favorites): migrate to backend API

This commit is contained in:
zetaloop
2026-03-01 22:36:50 +08:00
parent eba8fc7e65
commit 505d9c0168
3 changed files with 120 additions and 111 deletions
+65 -7
View File
@@ -1,10 +1,13 @@
"use client"
import { Button } from "@/components/ui/button"
import { addFavorite, isFavorited, listFavorites, removeFavorite } from "@/lib/api/favorites"
import { toApiError } from "@/lib/errors"
import { notifyInfo } from "@/lib/toast"
import { useRequireAuth } from "@/lib/use-require-auth"
import { useAuthStore } from "@/store/auth"
import { useFavoriteStore } from "@/store/favorites"
import { Heart } from "lucide-react"
import { useEffect, useState } from "react"
interface FavoriteButtonProps {
initialFavorited: boolean
@@ -15,21 +18,76 @@ interface FavoriteButtonProps {
export function FavoriteButton({ initialFavorited, targetType, targetId }: FavoriteButtonProps) {
const { requireAuth } = useRequireAuth()
const userId = useAuthStore((s) => s.user?.id)
const favoritedInStore = useFavoriteStore((state) =>
userId ? state.isFavorited(userId, targetType, targetId) : false,
)
const toggleFavorite = useFavoriteStore((state) => state.toggleFavorite)
const favorited = userId ? favoritedInStore : initialFavorited
const [favorited, setFavorited] = useState(initialFavorited)
const [pending, setPending] = useState(false)
useEffect(() => {
let cancelled = false
if (!userId) {
void Promise.resolve().then(() => {
if (cancelled) return
setFavorited(initialFavorited)
})
return () => {
cancelled = true
}
}
isFavorited(userId, targetType, targetId)
.then((value) => {
if (cancelled) return
setFavorited(value)
})
.catch((err: unknown) => {
if (cancelled) return
if (err instanceof Error && err.message === "UNAUTHORIZED") return
notifyInfo(toApiError(err).msg)
})
return () => {
cancelled = true
}
}, [initialFavorited, targetId, targetType, userId])
return (
<Button
variant={favorited ? "default" : "outline"}
size="sm"
className="gap-1.5"
disabled={pending}
onClick={() =>
requireAuth(() => {
if (pending) return
if (!userId) return
toggleFavorite(userId, targetType, targetId)
const prevFavorited = favorited
const nextFavorited = !prevFavorited
setFavorited(nextFavorited)
setPending(true)
const action = prevFavorited
? listFavorites().then((favorites) => {
const match = favorites.find(
(f) => f.targetType === targetType && f.targetId === targetId,
)
if (!match) return
return removeFavorite(match.id)
})
: addFavorite({ targetType, targetId }).then(() => {})
action
.catch((err: unknown) => {
setFavorited(prevFavorited)
if (err instanceof Error && err.message === "UNAUTHORIZED") {
notifyInfo("请先登录")
return
}
notifyInfo(toApiError(err).msg)
})
.finally(() => {
setPending(false)
})
})
}
>