99 lines
2.8 KiB
TypeScript
99 lines
2.8 KiB
TypeScript
"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 { Heart } from "lucide-react"
|
|
import { useEffect, useState } from "react"
|
|
|
|
interface FavoriteButtonProps {
|
|
initialFavorited: boolean
|
|
targetType: "player" | "shop"
|
|
targetId: string
|
|
}
|
|
|
|
export function FavoriteButton({ initialFavorited, targetType, targetId }: FavoriteButtonProps) {
|
|
const { requireAuth } = useRequireAuth()
|
|
const userId = useAuthStore((s) => s.user?.id)
|
|
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
|
|
|
|
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)
|
|
})
|
|
})
|
|
}
|
|
>
|
|
<Heart className={`h-4 w-4 ${favorited ? "fill-current" : ""}`} />
|
|
{favorited ? "已收藏" : "收藏"}
|
|
</Button>
|
|
)
|
|
}
|