1
0
Fork 0

fix(blackjack): show ten-value upcards correctly and auto-refresh the leaderboard

This commit is contained in:
Jason Fraley 2026-09-19 17:39:18 -04:00
parent 40b7cbb025
commit c2dc0fd593
2 changed files with 27 additions and 4 deletions

View file

@ -2,7 +2,7 @@
import { useEffect, useRef, useState } from "react";
import { cn } from "@/lib/utils";
import { handValue, type Card, type PublicPlayerView } from "@/lib/minigames/blackjack";
import { handValue, type Card, type PublicPlayerView, type Rank } from "@/lib/minigames/blackjack";
import type { BlackjackSnapshot } from "@/app/(frontend)/minigames/blackjack/actions";
import { Badge } from "@/components/ui/badge";
import { CardView } from "./CardView";
@ -40,6 +40,15 @@ function signedAmount(value: number): string {
return `${value >= 0 ? "+" : ""}${value.toLocaleString()}`;
}
// Upcard label reads the card's point value, not its rank: face cards (J/Q/K)
// count as 10, aces read "ace", and 2-10 show their pip count.
function upcardDisplay(rank: Rank | undefined): string {
if (!rank) return "";
if (rank === 14) return "ace";
if (rank >= 11) return "10";
return String(rank);
}
export function BlackjackFeltCanvas({
snapshot,
onSnapshot,
@ -196,8 +205,7 @@ export function BlackjackFeltCanvas({
)}
{view.dealer.holeHidden && view.dealer.cards.length > 0 && (
<span className="font-mono text-sm uppercase tracking-[0.2em] text-white/60">
Dealer showing{" "}
{view.dealer.cards[0]?.rank === 14 ? "ace" : (view.dealer.cards[0]?.rank ?? "")}
Dealer showing {upcardDisplay(view.dealer.cards[0]?.rank)}
</span>
)}
</div>

View file

@ -3,6 +3,7 @@
import { useEffect, useState } from "react";
import { Trophy } from "lucide-react";
import type { PresenceParticipant } from "@/hooks/useRealtimePresence";
import { PROFILE_UPDATE_EVENT } from "@/hooks/useGameTick";
import { cn } from "@/lib/utils";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
@ -84,6 +85,20 @@ export function BlackjackLeaderboard({
}: BlackjackLeaderboardProps) {
const [rows, setRows] = useState<readonly LeaderboardRow[] | null>(null);
const [failed, setFailed] = useState(false);
const [refreshTick, setRefreshTick] = useState(0);
// Read-only surface: keep it fresh without a page refresh. A profile update
// (a fellow player's result) and a 30s poll both bump refreshTick, which
// re-runs the fetch below. Rows only update on success, so no loading flash.
useEffect(() => {
const handleProfileUpdate = () => setRefreshTick((tick) => tick + 1);
window.addEventListener(PROFILE_UPDATE_EVENT, handleProfileUpdate);
const poll = window.setInterval(() => setRefreshTick((tick) => tick + 1), 30_000);
return () => {
window.removeEventListener(PROFILE_UPDATE_EVENT, handleProfileUpdate);
window.clearInterval(poll);
};
}, []);
useEffect(() => {
let cancelled = false;
@ -135,7 +150,7 @@ export function BlackjackLeaderboard({
return () => {
cancelled = true;
};
}, [currentUserId, refreshKey]);
}, [currentUserId, refreshKey, refreshTick]);
return (
<Card className="rounded-none">