121 lines
4.6 KiB
TypeScript
121 lines
4.6 KiB
TypeScript
|
|
import { type FormEvent, useState } from 'react'
|
||
|
|
import type { BossBattle, CreateBossResultInput } from '../types/game'
|
||
|
|
|
||
|
|
interface BossDefeatModalProps {
|
||
|
|
boss: BossBattle
|
||
|
|
onSubmit: (data: CreateBossResultInput) => void
|
||
|
|
onClose: () => void
|
||
|
|
isPending?: boolean
|
||
|
|
}
|
||
|
|
|
||
|
|
export function BossDefeatModal({ boss, onSubmit, onClose, isPending }: BossDefeatModalProps) {
|
||
|
|
const [result, setResult] = useState<'won' | 'lost'>('won')
|
||
|
|
const [attempts, setAttempts] = useState('1')
|
||
|
|
|
||
|
|
const handleSubmit = (e: FormEvent) => {
|
||
|
|
e.preventDefault()
|
||
|
|
onSubmit({
|
||
|
|
bossBattleId: boss.id,
|
||
|
|
result,
|
||
|
|
attempts: Number(attempts) || 1,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||
|
|
<div className="fixed inset-0 bg-black/50" onClick={onClose} />
|
||
|
|
<div className="relative bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full mx-4">
|
||
|
|
<div className="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
|
||
|
|
<h2 className="text-lg font-semibold">Battle: {boss.name}</h2>
|
||
|
|
<p className="text-sm text-gray-500 dark:text-gray-400">{boss.location}</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Boss team preview */}
|
||
|
|
{boss.pokemon.length > 0 && (
|
||
|
|
<div className="px-6 py-3 border-b border-gray-200 dark:border-gray-700">
|
||
|
|
<div className="flex flex-wrap gap-3">
|
||
|
|
{boss.pokemon
|
||
|
|
.sort((a, b) => a.order - b.order)
|
||
|
|
.map((bp) => (
|
||
|
|
<div key={bp.id} className="flex flex-col items-center">
|
||
|
|
{bp.pokemon.spriteUrl ? (
|
||
|
|
<img src={bp.pokemon.spriteUrl} alt={bp.pokemon.name} className="w-10 h-10" />
|
||
|
|
) : (
|
||
|
|
<div className="w-10 h-10 bg-gray-200 dark:bg-gray-700 rounded-full" />
|
||
|
|
)}
|
||
|
|
<span className="text-xs text-gray-500 dark:text-gray-400 capitalize">
|
||
|
|
{bp.pokemon.name}
|
||
|
|
</span>
|
||
|
|
<span className="text-xs font-medium text-gray-700 dark:text-gray-300">
|
||
|
|
Lv.{bp.level}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
<form onSubmit={handleSubmit}>
|
||
|
|
<div className="px-6 py-4 space-y-4">
|
||
|
|
<div>
|
||
|
|
<label className="block text-sm font-medium mb-2">Result</label>
|
||
|
|
<div className="flex gap-2">
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={() => setResult('won')}
|
||
|
|
className={`flex-1 px-3 py-2 text-sm font-medium rounded-md border transition-colors ${
|
||
|
|
result === 'won'
|
||
|
|
? 'bg-green-600 text-white border-green-600'
|
||
|
|
: 'border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
Won
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={() => setResult('lost')}
|
||
|
|
className={`flex-1 px-3 py-2 text-sm font-medium rounded-md border transition-colors ${
|
||
|
|
result === 'lost'
|
||
|
|
? 'bg-red-600 text-white border-red-600'
|
||
|
|
: 'border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
Lost
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div>
|
||
|
|
<label className="block text-sm font-medium mb-1">Attempts</label>
|
||
|
|
<input
|
||
|
|
type="number"
|
||
|
|
min={1}
|
||
|
|
value={attempts}
|
||
|
|
onChange={(e) => setAttempts(e.target.value)}
|
||
|
|
className="w-full px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="px-6 py-4 border-t border-gray-200 dark:border-gray-700 flex justify-end gap-3">
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={onClose}
|
||
|
|
className="px-4 py-2 text-sm font-medium rounded-md border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700"
|
||
|
|
>
|
||
|
|
Cancel
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
type="submit"
|
||
|
|
disabled={isPending}
|
||
|
|
className="px-4 py-2 text-sm font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50"
|
||
|
|
>
|
||
|
|
{isPending ? 'Saving...' : 'Save Result'}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|