Files
Dune/components/distrans.tsx
T

144 lines
4.8 KiB
TypeScript

'use client';
import { useId, useState } from 'react';
import type { Action, GameView } from '@/game/engine';
import { CardInspector, CardRules } from './card-inspector';
import { DistransTransferAction } from './distrans-transfer-action';
export function Distrans({
game,
act,
busy,
}: {
game: GameView;
act: (action: Action) => void;
busy: boolean;
}) {
const id = useId();
const [target, setTarget] = useState('');
const [selection, setSelection] = useState('');
const distrans = game.distrans;
if (!distrans) return null;
const choice =
distrans.choices.find((candidate) => candidate.recipient === target) ??
distrans.choices.find(
(candidate) => !candidate.blocked && candidate.cards.length > 0,
) ??
distrans.choices[0];
const recipient = game.players.find(
(player) => player.id === choice?.recipient,
);
const given =
choice?.cards.find((card) => card.id === selection) ?? choice?.cards[0];
const reason =
distrans.blocked ??
choice?.blocked ??
(!choice
? 'No recipient is available.'
: !given
? 'No other card is available to transfer to this player.'
: null);
return (
<details className="my-4 min-w-0">
<summary className="min-h-11 cursor-pointer py-3">
Distrans: transfer a card
</summary>
<div className="flex min-w-0 flex-col gap-4 py-3">
<p>
Give one other card from your hand to another player with room, then
discard Distrans. No spice is paid. The transfer happens immediately,
without a recipient confirmation or Karama response.
</p>
<p className="m-0 text-sm leading-6" aria-label="Provisional Distrans bid timing">
Provisional bid timing: you may transfer before the first bid or pass
on an ordinary auction lot. Once anyone bids or passes, that lot stays
blocked while unresolved. Special auctions keep their existing
restrictions.
</p>
<CardInspector card={distrans.card} />
{choice && (
<>
<label htmlFor={`${id}-target`}>Recipient</label>
<select
id={`${id}-target`}
className="min-h-11 w-full min-w-0"
value={choice.recipient}
disabled={busy}
onChange={(event) => {
setTarget(event.target.value);
setSelection('');
}}
>
{distrans.choices.map((candidate) => (
<option key={candidate.recipient} value={candidate.recipient}>
{game.players.find(
(player) => player.id === candidate.recipient,
)?.name ?? 'Player'}
{candidate.blocked ? ' — unavailable' : ''}
</option>
))}
</select>
{choice.cards.length > 0 && (
<>
<label htmlFor={`${id}-given`}>Your card to transfer</label>
<select
id={`${id}-given`}
className="min-h-11 w-full min-w-0"
value={given?.id ?? ''}
disabled={busy}
onChange={(event) => setSelection(event.target.value)}
>
{choice.cards.map((card) => (
<option key={card.id} value={card.id}>
{card.name}
</option>
))}
</select>
{given && (
<div className="flex min-w-0 flex-col gap-3">
<CardRules card={given} />
<CardInspector card={given} />
</div>
)}
</>
)}
</>
)}
{reason && (
<p id={`${id}-reason`} className="notice">
{reason}
</p>
)}
<DistransTransferAction
card={distrans.card}
recipient={choice ? { id: choice.recipient, name: recipient?.name } : undefined}
given={given}
reason={reason}
reasonId={`${id}-reason`}
busy={busy}
act={act}
/>
{!!choice?.unavailable.length && (
<div
className="flex min-w-0 flex-col gap-3"
aria-labelledby={`${id}-unavailable`}
>
<h4 id={`${id}-unavailable`}>
Your cards unavailable for this transfer
</h4>
<ul className="flex list-none flex-col gap-4 p-0">
{choice.unavailable.map(({ card, reason: blocked }) => (
<li key={card.id} className="flex min-w-0 flex-col gap-2">
<strong>{card.name}</strong>
<p>{blocked}</p>
<CardInspector card={card} />
</li>
))}
</ul>
</div>
)}
</div>
</details>
);
}