'use client'; import type { Action } from '@/game/engine'; import { Button } from './ui/button'; /** Public order and responses; choices contain only this viewer's legal cards. */ export type SaphoArrivalOrderView = { event: string; revision: number; order: string[]; passed: string[]; choices: { card: string; mode: 'first' | 'last' }[]; }; export type SaphoArrivalOrderProps = { view: SaphoArrivalOrderView; me: string; busy: boolean; name: (player: string) => string; act: (action: Action) => void; }; function current(props: SaphoArrivalOrderProps, view: SaphoArrivalOrderView, event: string, revision: number): boolean { return !props.busy && props.view === view && view.event === event && view.revision === revision && typeof event === 'string' && event.length > 0 && Number.isSafeInteger(revision) && revision >= 0 && view.order.includes(props.me) && !view.passed.includes(props.me); } /** Both original reaction owners can continue without revealing their hands. */ export function SaphoArrivalOrderPass(props: SaphoArrivalOrderProps) { const { view } = props, event = view.event, revision = view.revision; const canAct = () => current(props, view, event, revision); return ; } export function SaphoArrivalOrderChoiceButton(props: SaphoArrivalOrderProps & { choice: SaphoArrivalOrderView['choices'][number]; }) { const { view, choice } = props, event = view.event, revision = view.revision; const card = choice.card, mode = choice.mode; const canAct = () => current(props, view, event, revision) && typeof card === 'string' && card.length > 0 && (mode === 'first' || mode === 'last') && choice.card === card && choice.mode === mode && view.choices.some(item => item.card === card && item.mode === mode); return ; } /** Do not infer eligibility from a hand: the server supplies the public window * and only the current viewer's privately quoted card choices. */ export function SaphoArrivalOrder(props: SaphoArrivalOrderProps) { const { view, me, name } = props; const eligible = view.order.includes(me), passed = view.passed.includes(me); return

Ambassador and Terror reaction order

Both reactions follow the same entry. Before either begins, their owners may continue or use an available order change.

Current order: {view.order.map((player, index) => {index > 0 && ' → '}{name(player)})}.

{view.passed.length} of {view.order.length} players have finished this choice.

This ordering procedure is a provisional interpretation.

{eligible && !passed ? <> {view.choices.map(choice => )} :

{eligible ? 'You have finished this choice.' : 'Waiting for the reaction owners.'}

}
; }