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>
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
import { useState, useMemo } from 'react'
|
||||
import type {
|
||||
EncounterDetail,
|
||||
UpdateEncounterInput,
|
||||
CreateEncounterInput,
|
||||
} from '../types'
|
||||
import type { EncounterDetail, UpdateEncounterInput, CreateEncounterInput } from '../types'
|
||||
import { useEvolutions, useForms } from '../hooks/useEncounters'
|
||||
import { TypeBadge } from './TypeBadge'
|
||||
import { formatEvolutionMethod } from '../utils/formatEvolution'
|
||||
@@ -25,24 +21,14 @@ export function StatusChangeModal({
|
||||
region,
|
||||
onCreateEncounter,
|
||||
}: StatusChangeModalProps) {
|
||||
const {
|
||||
pokemon,
|
||||
currentPokemon,
|
||||
route,
|
||||
nickname,
|
||||
catchLevel,
|
||||
faintLevel,
|
||||
deathCause,
|
||||
} = encounter
|
||||
const { pokemon, currentPokemon, route, nickname, catchLevel, faintLevel, deathCause } = encounter
|
||||
const isDead = faintLevel !== null
|
||||
const displayPokemon = currentPokemon ?? pokemon
|
||||
const [showConfirm, setShowConfirm] = useState(false)
|
||||
const [showEvolve, setShowEvolve] = useState(false)
|
||||
const [showFormChange, setShowFormChange] = useState(false)
|
||||
const [showShedConfirm, setShowShedConfirm] = useState(false)
|
||||
const [pendingEvolutionId, setPendingEvolutionId] = useState<number | null>(
|
||||
null
|
||||
)
|
||||
const [pendingEvolutionId, setPendingEvolutionId] = useState<number | null>(null)
|
||||
const [shedNickname, setShedNickname] = useState('')
|
||||
const [deathLevel, setDeathLevel] = useState('')
|
||||
const [cause, setCause] = useState('')
|
||||
@@ -115,12 +101,7 @@ export function StatusChangeModal({
|
||||
onClick={onClose}
|
||||
className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
@@ -142,7 +123,7 @@ export function StatusChangeModal({
|
||||
/>
|
||||
) : (
|
||||
<div className="w-16 h-16 rounded-full bg-gray-300 dark:bg-gray-600 flex items-center justify-center text-xl font-bold text-gray-600 dark:text-gray-300">
|
||||
{displayPokemon.name[0].toUpperCase()}
|
||||
{displayPokemon.name[0]?.toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
@@ -179,55 +160,46 @@ export function StatusChangeModal({
|
||||
</div>
|
||||
{faintLevel !== null && (
|
||||
<div className="text-sm text-gray-700 dark:text-gray-300">
|
||||
<span className="text-gray-500 dark:text-gray-400">
|
||||
Level at death:
|
||||
</span>{' '}
|
||||
<span className="text-gray-500 dark:text-gray-400">Level at death:</span>{' '}
|
||||
{faintLevel}
|
||||
</div>
|
||||
)}
|
||||
{deathCause && (
|
||||
<div className="text-sm text-gray-700 dark:text-gray-300">
|
||||
<span className="text-gray-500 dark:text-gray-400">
|
||||
Cause:
|
||||
</span>{' '}
|
||||
{deathCause}
|
||||
<span className="text-gray-500 dark:text-gray-400">Cause:</span> {deathCause}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Alive pokemon: actions */}
|
||||
{!isDead &&
|
||||
!showConfirm &&
|
||||
!showEvolve &&
|
||||
!showFormChange &&
|
||||
!showShedConfirm && (
|
||||
<div className="flex gap-3">
|
||||
{!isDead && !showConfirm && !showEvolve && !showFormChange && !showShedConfirm && (
|
||||
<div className="flex gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowEvolve(true)}
|
||||
className="flex-1 px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
Evolve
|
||||
</button>
|
||||
{forms && forms.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowEvolve(true)}
|
||||
className="flex-1 px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors"
|
||||
onClick={() => setShowFormChange(true)}
|
||||
className="flex-1 px-4 py-2 bg-purple-600 text-white rounded-lg font-medium hover:bg-purple-700 transition-colors"
|
||||
>
|
||||
Evolve
|
||||
Change Form
|
||||
</button>
|
||||
{forms && forms.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowFormChange(true)}
|
||||
className="flex-1 px-4 py-2 bg-purple-600 text-white rounded-lg font-medium hover:bg-purple-700 transition-colors"
|
||||
>
|
||||
Change Form
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowConfirm(true)}
|
||||
className="flex-1 px-4 py-2 bg-red-600 text-white rounded-lg font-medium hover:bg-red-700 transition-colors"
|
||||
>
|
||||
Mark as Dead
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowConfirm(true)}
|
||||
className="flex-1 px-4 py-2 bg-red-600 text-white rounded-lg font-medium hover:bg-red-700 transition-colors"
|
||||
>
|
||||
Mark as Dead
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Evolution selection */}
|
||||
{!isDead && showEvolve && (
|
||||
@@ -245,14 +217,10 @@ export function StatusChangeModal({
|
||||
</button>
|
||||
</div>
|
||||
{evolutionsLoading && (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Loading evolutions...
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">Loading evolutions...</p>
|
||||
)}
|
||||
{!evolutionsLoading && normalEvolutions.length === 0 && (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
No evolutions available
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">No evolutions available</p>
|
||||
)}
|
||||
{!evolutionsLoading && normalEvolutions.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
@@ -272,7 +240,7 @@ export function StatusChangeModal({
|
||||
/>
|
||||
) : (
|
||||
<div className="w-10 h-10 rounded-full bg-gray-300 dark:bg-gray-600 flex items-center justify-center text-sm font-bold text-gray-600 dark:text-gray-300">
|
||||
{evo.toPokemon.name[0].toUpperCase()}
|
||||
{evo.toPokemon.name[0]?.toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-left">
|
||||
@@ -320,16 +288,12 @@ export function StatusChangeModal({
|
||||
/>
|
||||
) : (
|
||||
<div className="w-12 h-12 rounded-full bg-gray-300 dark:bg-gray-600 flex items-center justify-center text-sm font-bold text-gray-600 dark:text-gray-300">
|
||||
{shedCompanion.toPokemon.name[0].toUpperCase()}
|
||||
{shedCompanion.toPokemon.name[0]?.toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
<p className="text-sm text-amber-800 dark:text-amber-300">
|
||||
{displayPokemon.name} shed its shell! Would you also like to
|
||||
add{' '}
|
||||
<span className="font-semibold">
|
||||
{shedCompanion.toPokemon.name}
|
||||
</span>
|
||||
?
|
||||
{displayPokemon.name} shed its shell! Would you also like to add{' '}
|
||||
<span className="font-semibold">{shedCompanion.toPokemon.name}</span>?
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -338,8 +302,7 @@ export function StatusChangeModal({
|
||||
htmlFor="shed-nickname"
|
||||
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
||||
>
|
||||
Nickname{' '}
|
||||
<span className="font-normal text-gray-400">(optional)</span>
|
||||
Nickname <span className="font-normal text-gray-400">(optional)</span>
|
||||
</label>
|
||||
<input
|
||||
id="shed-nickname"
|
||||
@@ -366,9 +329,7 @@ export function StatusChangeModal({
|
||||
onClick={() => applyEvolution(true)}
|
||||
className="flex-1 px-4 py-2 bg-amber-600 text-white rounded-lg font-medium hover:bg-amber-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
{isPending
|
||||
? 'Saving...'
|
||||
: `Add ${shedCompanion.toPokemon.name}`}
|
||||
{isPending ? 'Saving...' : `Add ${shedCompanion.toPokemon.name}`}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -400,14 +361,10 @@ export function StatusChangeModal({
|
||||
className="w-full flex items-center gap-3 p-3 rounded-lg border border-gray-200 dark:border-gray-600 hover:bg-purple-50 dark:hover:bg-purple-900/20 hover:border-purple-300 dark:hover:border-purple-600 transition-colors disabled:opacity-50"
|
||||
>
|
||||
{form.spriteUrl ? (
|
||||
<img
|
||||
src={form.spriteUrl}
|
||||
alt={form.name}
|
||||
className="w-10 h-10"
|
||||
/>
|
||||
<img src={form.spriteUrl} alt={form.name} className="w-10 h-10" />
|
||||
) : (
|
||||
<div className="w-10 h-10 rounded-full bg-gray-300 dark:bg-gray-600 flex items-center justify-center text-sm font-bold text-gray-600 dark:text-gray-300">
|
||||
{form.name[0].toUpperCase()}
|
||||
{form.name[0]?.toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-left">
|
||||
@@ -441,8 +398,7 @@ export function StatusChangeModal({
|
||||
htmlFor="death-level"
|
||||
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
||||
>
|
||||
Level at Death{' '}
|
||||
<span className="font-normal text-gray-400">(optional)</span>
|
||||
Level at Death <span className="font-normal text-gray-400">(optional)</span>
|
||||
</label>
|
||||
<input
|
||||
id="death-level"
|
||||
@@ -461,8 +417,7 @@ export function StatusChangeModal({
|
||||
htmlFor="death-cause"
|
||||
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
||||
>
|
||||
Cause of Death{' '}
|
||||
<span className="font-normal text-gray-400">(optional)</span>
|
||||
Cause of Death <span className="font-normal text-gray-400">(optional)</span>
|
||||
</label>
|
||||
<input
|
||||
id="death-cause"
|
||||
@@ -498,11 +453,7 @@ export function StatusChangeModal({
|
||||
|
||||
{/* Footer for dead/no-confirm/no-evolve views */}
|
||||
{(isDead ||
|
||||
(!isDead &&
|
||||
!showConfirm &&
|
||||
!showEvolve &&
|
||||
!showFormChange &&
|
||||
!showShedConfirm)) && (
|
||||
(!isDead && !showConfirm && !showEvolve && !showFormChange && !showShedConfirm)) && (
|
||||
<div className="px-6 py-4 border-t border-gray-200 dark:border-gray-700 flex justify-end">
|
||||
<button
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user