feat(favorites): migrate to backend API
This commit is contained in:
@@ -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)
|
||||
})
|
||||
})
|
||||
}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user