"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; import { Gift, Users, ChevronRight, Flame } from "lucide-react"; import type { DailyRewardStatus } from "@spinza/shared"; import { api } from "@/lib/api"; import { toast, useSession } from "@/lib/store"; import { useApi } from "@/lib/use-api"; import { countdown, cn } from "@/lib/utils"; import { Button, Credits, Skeleton } from "@/components/ui"; interface ClaimResponse { amount: number; streakDay: number; balance: number; nextAvailableAt: string; xp: { xp: number; level: number; leveledUp?: boolean } | null; } /** Lobby strip: daily reward availability + live players. */ export function RewardsStrip({ livePlayers }: { livePlayers: number }) { const { data, loading, error, setData, reload } = useApi("/api/rewards/daily"); const setBalance = useSession((s) => s.setBalance); const setUserXp = useSession((s) => s.setUserXp); const [claiming, setClaiming] = useState(false); const [, tick] = useState(0); useEffect(() => { if (!data || data.available) return; const t = setInterval(() => tick((n) => n + 1), 1000); return () => clearInterval(t); }, [data]); const claim = async () => { if (claiming) return; setClaiming(true); try { const res = await api("/api/rewards/daily/claim", { method: "POST" }); setBalance(res.balance); if (res.xp) setUserXp(res.xp.xp, res.xp.level); toast({ title: `+${res.amount.toLocaleString("en-US")} SC`, description: `Daily reward · day ${res.streakDay} of ${data?.schedule.length ?? 7}`, tone: "credit" }); setData((d) => (d ? { ...d, available: false, claimedToday: true, streakDay: res.streakDay, nextAvailableAt: res.nextAvailableAt } : d)); } catch (e) { toast({ title: "Could not claim", description: e instanceof Error ? e.message : undefined, tone: "danger" }); void reload(); } finally { setClaiming(false); } }; return (
{loading && !data ? ( <> ) : error && !data ? ( <>
Daily reward
Unavailable right now.
) : data ? ( <>
{data.available ? "Your daily reward is ready" : "Daily reward claimed"} {data.streakDay > 1 ? ( {data.streakDay}-day streak ) : null}
{data.available ? ( <> Claim · day {Math.min(data.streakDay + 1, data.schedule.length)} of {data.schedule.length} ) : ( <> Next reward in {countdown(data.nextAvailableAt)} )}
) : null}
{data?.available ? ( ) : ( )}
{livePlayers.toLocaleString("en-US")}
{livePlayers === 1 ? "player" : "players"} live now
); }