- login-form.tsx: suppress unused-vars warning for emailChecked state - bookmark-button.tsx: use function initializer for isLoading to avoid sync setState in effect - saved-games.ts: remove unused 'set' parameter from check endpoint
105 lines
2.8 KiB
TypeScript
105 lines
2.8 KiB
TypeScript
"use client"
|
|
|
|
import { useState, useEffect } from "react"
|
|
import { Bookmark, Loader2 } from "lucide-react"
|
|
import { motion, AnimatePresence } from "motion/react"
|
|
import { useSession } from "@/lib/auth-client"
|
|
|
|
interface BookmarkButtonProps {
|
|
gameId: string
|
|
className?: string
|
|
}
|
|
|
|
export function BookmarkButton({ gameId, className = "" }: BookmarkButtonProps) {
|
|
const { data: session } = useSession()
|
|
const [isSaved, setIsSaved] = useState(false)
|
|
const [isLoading, setIsLoading] = useState(() => !session)
|
|
const [isToggling, setIsToggling] = useState(false)
|
|
|
|
useEffect(() => {
|
|
if (!session) return
|
|
|
|
async function checkSaved() {
|
|
try {
|
|
const res = await fetch(`/api/user/me/saved-games/check/${gameId}`)
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
setIsSaved(data.saved)
|
|
}
|
|
} catch (err) {
|
|
console.error("Failed to check saved status:", err)
|
|
} finally {
|
|
setIsLoading(false)
|
|
}
|
|
}
|
|
|
|
checkSaved()
|
|
}, [session, gameId])
|
|
|
|
const toggleSave = async () => {
|
|
if (!session || isToggling) return
|
|
|
|
setIsToggling(true)
|
|
try {
|
|
if (isSaved) {
|
|
const res = await fetch(`/api/user/me/saved-games/${gameId}`, {
|
|
method: "DELETE",
|
|
})
|
|
if (res.ok) {
|
|
setIsSaved(false)
|
|
}
|
|
} else {
|
|
const res = await fetch("/api/user/me/saved-games", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ gameId }),
|
|
})
|
|
if (res.ok) {
|
|
setIsSaved(true)
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error("Failed to toggle saved game:", err)
|
|
} finally {
|
|
setIsToggling(false)
|
|
}
|
|
}
|
|
|
|
if (!session || isLoading) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<motion.button
|
|
whileTap={{ scale: 0.9 }}
|
|
onClick={toggleSave}
|
|
disabled={isToggling}
|
|
className={`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors cursor-pointer ${
|
|
isSaved
|
|
? "bg-primary/10 border-primary/30 text-primary"
|
|
: "bg-text/5 border-border text-text/50 hover:text-text hover:border-primary/30"
|
|
} ${className}`}
|
|
>
|
|
<AnimatePresence mode="wait">
|
|
{isToggling ? (
|
|
<Loader2 className="h-4 w-4 animate-spin" />
|
|
) : (
|
|
<motion.div
|
|
key={isSaved ? "saved" : "not-saved"}
|
|
initial={{ scale: 0.8 }}
|
|
animate={{ scale: 1 }}
|
|
exit={{ scale: 0.8 }}
|
|
>
|
|
<Bookmark
|
|
className={`h-4 w-4 ${isSaved ? "fill-primary" : ""}`}
|
|
/>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
<span className="text-sm font-medium">
|
|
{isSaved ? "Saved" : "Save"}
|
|
</span>
|
|
</motion.button>
|
|
)
|
|
}
|