Files
Dune/components/richese-auction-countdown.tsx
T
Quintine 7fc6f1cd43
Verify and publish checkpoint container / container (push) Canceled after 0s
Time sequential Richese auctions
2026-10-29 02:11:18 +11:00

49 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { useEffect, useState } from 'react';
import type { AuctionClockView } from '@/game/auction-clock';
import type { RicheseAuctionMethod } from '@/game/richese-auction';
/** Display only: the authoritative room clock performs the expiry action. */
export function RicheseAuctionCountdown({ clock, playerName, method, paused = false }: {
clock: AuctionClockView | null;
playerName: string;
method: Exclude<RicheseAuctionMethod, 'silent'>;
paused?: boolean;
}) {
const [local, setLocal] = useState<{ clock: AuctionClockView; remainingMs: number } | null>(null);
const running = !!clock?.event && clock.running && !paused;
useEffect(() => {
if (!clock || !running || clock.remainingMs <= 0) return;
const startedAt = performance.now();
const timer = setInterval(() => {
const remainingMs = Math.max(0, clock.remainingMs - Math.max(0, performance.now() - startedAt));
setLocal({ clock, remainingMs });
if (remainingMs === 0) clearInterval(timer);
}, 200);
return () => clearInterval(timer);
}, [clock, running]);
if (!clock) return null;
const remainingMs = running && local?.clock === clock ? local.remainingMs : Math.max(0, clock.remainingMs);
const seconds = Math.ceil(remainingMs / 1000);
const name = method === 'onceAround' ? 'Once Around' : 'Black Market';
const status = clock.event !== null && seconds === 0
? `${paused ? 'Auction paused. ' : ''}Awaiting server resolution.`
: clock.event === null
? `${paused ? 'Auction paused. ' : ''}Clock starts when bidding is ready.`
: paused ? 'Auction paused.'
: !clock.running ? 'Bidding clock held while the current game decision finishes.'
: `${playerName} may bid or pass.`;
return <section className="notice space-y-2" aria-label={`${name} auction countdown`} data-testid="richese-auction-countdown">
<output className="block">{status}</output>
<p role="timer" aria-live="off" aria-atomic="true" aria-label={`${playerName}’s remaining bidding time`}
className="font-semibold tabular-nums">{seconds} {seconds === 1 ? 'second' : 'seconds'} {clock.event === null ? 'available' : 'remaining'}</p>
<p className="fine">This timed {name} auction gives each bidder 10 seconds to bid or pass. The server controls the deadline and resolves expiry.</p>
{method === 'onceAround' && <>
<p className="fine">Once Around timing is a provisional online interpretation of the standard bid deadline.</p>
<p className="fine">If passing would break a binding Truthtrance answer, the server submits only its required legal bid; normal payment still applies.</p>
</>}
</section>;
}