36 lines
1.6 KiB
TypeScript
36 lines
1.6 KiB
TypeScript
'use client';
|
||
|
||
import { useId, useState } from 'react';
|
||
import type { Action, GameView } from '@/game/engine';
|
||
|
||
/** The server exposes the current optional opportunity only to its Emperor. */
|
||
export function EmperorAuctionGift({ game, act, busy }: {
|
||
game: GameView;
|
||
act: (action: Action) => void;
|
||
busy: boolean;
|
||
}) {
|
||
const id = useId();
|
||
const [raw, setRaw] = useState('1');
|
||
const offer = game.emperorAuctionGift;
|
||
if (!offer) return null;
|
||
const amount = /^[1-9]\d*$/.test(raw) ? Number(raw) : NaN;
|
||
const canShare = !busy && Number.isSafeInteger(amount) && amount >= 1 && amount <= offer.maximum;
|
||
const recipient = game.players.find(player => player.id === offer.recipient)?.name ?? 'your ally';
|
||
|
||
return <section className="notice min-w-0 space-y-3 break-words" aria-label="Emperor auction gift">
|
||
<h3>Share spice with {recipient}</h3>
|
||
<p className="fine">The winning bid and its committed ally payment split remain unchanged. Your ally chooses how to pay after the gift’s Karama response.</p>
|
||
<label htmlFor={`${id}-amount`}>Spice to share</label>
|
||
<input id={`${id}-amount`} type="number" inputMode="numeric" min={1} max={offer.maximum}
|
||
step={1} value={raw} disabled={busy || offer.maximum < 1} onChange={event => setRaw(event.target.value)} />
|
||
<button type="button" className="game-action" disabled={!canShare}
|
||
onClick={() => { if (canShare) act({type:'emperorGift', amount}); }}>
|
||
Share spice
|
||
</button>
|
||
<button type="button" className="game-action" disabled={busy}
|
||
onClick={() => { if (!busy) act({type:'emperorAuctionGiftContinue', event:offer.event}); }}>
|
||
Continue to payment
|
||
</button>
|
||
</section>;
|
||
}
|