elmeg-demo/frontend/components/chase/mark-caught-button.tsx
fullsizemalt 49e025d3bf
Some checks are pending
Deploy Elmeg / deploy (push) Waiting to run
fix: commit all pending changes (home, leaderboard, slug cleanup)
2025-12-24 12:06:35 -08:00

112 lines
3.4 KiB
TypeScript

"use client"
import { useState, useEffect } from "react"
import { Button } from "@/components/ui/button"
import { Target, Check, Loader2 } from "lucide-react"
import { getApiUrl } from "@/lib/api-config"
import { useAuth } from "@/contexts/auth-context"
interface ChaseSong {
id: number
song_id: number
song_title: string
caught_at: string | null
caught_show_id: number | null
}
interface MarkCaughtButtonProps {
songId: number
songTitle: string
showId: number
className?: string
}
export function MarkCaughtButton({ songId, songTitle, showId, className }: MarkCaughtButtonProps) {
const { user, token } = useAuth()
const [chaseSong, setChaseSong] = useState<ChaseSong | null>(null)
const [marking, setMarking] = useState(false)
useEffect(() => {
if (!user || !token) return
fetch(`${getApiUrl()}/chase/songs`, {
headers: { Authorization: `Bearer ${token}` }
})
.then(res => res.ok ? res.json() : [])
.then((songs: ChaseSong[]) => {
const match = songs.find(s => s.song_id === songId)
setChaseSong(match || null)
})
.catch(() => setChaseSong(null))
}, [user, token, songId])
const handleMarkCaught = async () => {
if (!chaseSong || !token) return
setMarking(true)
try {
const res = await fetch(`${getApiUrl()}/chase/songs/${chaseSong.id}/caught?show_id=${showId}`, {
method: "POST",
headers: { Authorization: `Bearer ${token}` }
})
if (!res.ok) throw new Error("Failed to mark caught")
// Update local state
setChaseSong({ ...chaseSong, caught_at: new Date().toISOString(), caught_show_id: showId })
} catch (err) {
console.error(err)
alert("Failed to mark song as caught")
} finally {
setMarking(false)
}
}
// Not logged in or not chasing this song
if (!user || !chaseSong) return null
// Already caught at THIS show
if (chaseSong.caught_show_id === showId) {
return (
<span
className="inline-flex items-center gap-1 text-xs text-green-600 dark:text-green-400 font-medium"
title={`You caught ${songTitle} at this show!`}
>
<Check className="h-3 w-3" />
Caught!
</span>
)
}
// Already caught at another show
if (chaseSong.caught_at) {
return (
<span
className="inline-flex items-center gap-1 text-xs text-muted-foreground"
title={`You already caught ${songTitle} at another show`}
>
<Check className="h-3 w-3" />
Caught
</span>
)
}
// Chasing but not yet caught
return (
<Button
variant="ghost"
size="sm"
onClick={handleMarkCaught}
disabled={marking}
title={`You're chasing ${songTitle}! Mark it as caught at this show.`}
className={`h-6 px-2 text-xs gap-1 text-amber-600 hover:text-amber-700 hover:bg-amber-50 dark:text-amber-400 dark:hover:bg-amber-950/50 ${className}`}
>
{marking ? (
<Loader2 className="h-3 w-3 animate-spin" />
) : (
<Target className="h-3 w-3" />
)}
Mark Caught
</Button>
)
}