Files
nuzlocke-tracker/frontend/src/components/TransferModal.tsx
Julian Tabel 3a64661760
Some checks failed
CI / backend-lint (push) Failing after 1m4s
CI / actions-lint (push) Failing after 6s
CI / frontend-lint (push) Successful in 59s
Align repo config with global development standards
- Add missing tsconfig strictness flags (noUncheckedIndexedAccess,
  exactOptionalPropertyTypes, noImplicitOverride,
  noPropertyAccessFromIndexSignature) and fix all resulting type errors
- Replace ESLint/Prettier with oxlint 1.48.0 and oxfmt 0.33.0
- Pin all frontend and backend dependencies to exact versions
- Pin GitHub Actions to SHA hashes with persist-credentials: false
- Fix CI Python version mismatch (3.12 -> 3.14) and ruff target-version
- Add vitest 4.0.18 with jsdom environment for frontend testing
- Add ty 0.0.17 for Python type checking (non-blocking in CI)
- Add actionlint and zizmor CI job for workflow linting and security audit
- Add Dependabot config for npm, pip, and github-actions
- Update CLAUDE.md and pre-commit hooks to reflect new tooling
- Ignore Claude Code sandbox artifacts in gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 20:39:41 +01:00

108 lines
4.3 KiB
TypeScript

import { useState } from 'react'
import type { EncounterDetail } from '../types'
interface TransferModalProps {
hofTeam: EncounterDetail[]
onSubmit: (encounterIds: number[]) => void
onSkip: () => void
isPending: boolean
}
export function TransferModal({ hofTeam, onSubmit, onSkip, isPending }: TransferModalProps) {
const [selected, setSelected] = useState<Set<number>>(() => new Set(hofTeam.map((e) => e.id)))
const toggle = (id: number) => {
setSelected((prev) => {
const next = new Set(prev)
if (next.has(id)) {
next.delete(id)
} else {
next.add(id)
}
return next
})
}
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
<div className="fixed inset-0 bg-black/50" />
<div className="relative bg-white dark:bg-gray-800 rounded-xl shadow-xl max-w-lg w-full max-h-[90vh] overflow-y-auto">
<div className="sticky top-0 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 px-6 py-4 rounded-t-xl">
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">
Transfer Pokemon to Next Leg
</h2>
<p className="text-sm text-gray-500 dark:text-gray-400 mt-1">
Selected Pokemon will be bred down to their base form and appear as level 1 encounters
in the next leg.
</p>
</div>
<div className="px-6 py-4">
<div className="grid grid-cols-3 gap-2">
{hofTeam.map((enc) => {
const displayPokemon = enc.currentPokemon ?? enc.pokemon
const isSelected = selected.has(enc.id)
return (
<button
key={enc.id}
type="button"
onClick={() => toggle(enc.id)}
className={`flex flex-col items-center p-3 rounded-lg border-2 text-center transition-colors ${
isSelected
? 'border-indigo-500 bg-indigo-50 dark:bg-indigo-900/20'
: 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'
}`}
>
{displayPokemon.spriteUrl ? (
<img
src={displayPokemon.spriteUrl}
alt={displayPokemon.name}
className="w-14 h-14"
/>
) : (
<div className="w-14 h-14 rounded-full bg-gray-200 dark:bg-gray-600 flex items-center justify-center text-lg font-bold">
{displayPokemon.name[0]?.toUpperCase()}
</div>
)}
<span className="text-xs font-medium text-gray-700 dark:text-gray-300 mt-1 capitalize">
{enc.nickname || displayPokemon.name}
</span>
{enc.nickname && (
<span className="text-[10px] text-gray-400">{displayPokemon.name}</span>
)}
<span className="text-[10px] text-gray-400 mt-0.5">{enc.route.name}</span>
</button>
)
})}
</div>
</div>
<div className="sticky bottom-0 bg-white dark:bg-gray-800 border-t border-gray-200 dark:border-gray-700 px-6 py-4 rounded-b-xl flex items-center justify-between">
<button
type="button"
onClick={onSkip}
disabled={isPending}
className="text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 disabled:opacity-50"
>
Skip (No Transfers)
</button>
<div className="flex items-center gap-3">
<span className="text-sm text-gray-400 dark:text-gray-500">
{selected.size}/{hofTeam.length} selected
</span>
<button
type="button"
disabled={selected.size === 0 || isPending}
onClick={() => onSubmit([...selected])}
className="px-4 py-2 bg-indigo-600 text-white rounded-lg font-medium hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{isPending ? 'Transferring...' : 'Transfer & Advance'}
</button>
</div>
</div>
</div>
</div>
)
}