testsAndMisc/poker-stakes/src/App.tsx
Krzysztof kuhy Rudnicki 72a5e28456 Track poker-stakes so the file-length cap can reach it
The directory has existed on disk with 58 untracked files, four of them over
the 250-line cap. An untracked file is invisible to every pre-commit hook, so
those violations could not be fixed or gated while it stayed that way -- and
its CI workflow was untracked too, so nothing ran against it.

Landed with its already-written evidence artifact and a contract, since this
crosses the 4-file threshold.

Verified before staging: 58 plain text source/config files, no binaries, no
node_modules, no build output. npm run check passes -- typecheck, eslint
--max-warnings 0, and 220 tests at 100% statements/branches/functions/lines.

Splitting its four oversized files is deliberately a separate commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
2026-08-16 15:19:07 +02:00

59 lines
2.5 KiB
TypeScript

import { useState } from 'react'
import type { ReactElement } from 'react'
import { BettingControls } from './ui/BettingControls'
import { BuyInScreen } from './ui/BuyInScreen'
import { CashOutPanel } from './ui/CashOutPanel'
import { DebtHistoryPanel } from './ui/DebtHistoryPanel'
import { HandLog } from './ui/HandLog'
import { Table } from './ui/Table'
import { useGame } from './ui/useGame'
interface AppProps {
/** Injected so tests can drive a scripted in-memory ledger; defaults to the real localStorage. */
storage?: Storage
/** Injected so tests can script a deterministic deal; defaults to a per-mount clock read. */
seed?: number
}
export const App = ({ storage = localStorage, seed }: AppProps = {}): ReactElement => {
// Lazy init: `Date.now()` must be read once per mount, not on every render — an inline default
// would make the component impure and re-seed the deck on each re-render.
const [dealSeed] = useState(() => seed ?? Date.now())
const { state, buyIn, dealHand, submitPlayerAction, cashOut, logDebtProgress } = useGame(storage, dealSeed)
const { debtLoad, buyIn: activeBuyIn, session, handPhase } = state
return (
<main className="frame">
<header className="masthead">
<h1>Poker Stakes</h1>
<p>Lose the hand, pay the price — in pushups, problems or reviews.</p>
</header>
{session === null || activeBuyIn === null ? (
<BuyInScreen debtLoad={debtLoad} onBuyIn={buyIn} onLogDebtProgress={logDebtProgress} />
) : (
<>
<Table session={session} handPhase={handPhase} />
{handPhase?.kind === 'awaiting' && (
<BettingControls betting={handPhase.step.betting} onAction={submitPlayerAction} />
)}
{/*
`handPhase` is never null while a session exists — `useGame.buyIn` deals the opening
hand as part of sitting down — so the only two states here are the awaiting/between
pair above and below.
*/}
{handPhase?.kind === 'betweenHands' && (
<>
<HandLog lastResult={handPhase.lastResult} />
<button type="button" className="button button--primary" onClick={dealHand}>
Deal next hand
</button>
</>
)}
<CashOutPanel session={session} buyIn={activeBuyIn} handPhase={handPhase} onCashOut={cashOut} />
</>
)}
<DebtHistoryPanel debtLoad={debtLoad} onLogDebtProgress={logDebtProgress} />
</main>
)
}