fix(blackjack): show ten-value upcards correctly and auto-refresh the leaderboard
This commit is contained in:
parent
40b7cbb025
commit
c2dc0fd593
2 changed files with 27 additions and 4 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
Loading…
Reference in a new issue