119 lines
4.7 KiB
TypeScript
119 lines
4.7 KiB
TypeScript
|
|
import { useState } from 'react'
|
||
|
|
import type { SurvivorEncounter } from '../types'
|
||
|
|
|
||
|
|
interface TransferModalProps {
|
||
|
|
survivors: SurvivorEncounter[]
|
||
|
|
onSubmit: (encounterIds: number[]) => void
|
||
|
|
onSkip: () => void
|
||
|
|
isPending: boolean
|
||
|
|
}
|
||
|
|
|
||
|
|
export function TransferModal({ survivors, onSubmit, onSkip, isPending }: TransferModalProps) {
|
||
|
|
const [selected, setSelected] = useState<Set<number>>(
|
||
|
|
() => new Set(survivors.map((s) => s.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">
|
||
|
|
{survivors.length === 0 ? (
|
||
|
|
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-8">
|
||
|
|
No surviving Pokemon to transfer.
|
||
|
|
</p>
|
||
|
|
) : (
|
||
|
|
<div className="grid grid-cols-3 gap-2">
|
||
|
|
{survivors.map((survivor) => {
|
||
|
|
const displayPokemon = survivor.currentPokemon ?? survivor.pokemon
|
||
|
|
const isSelected = selected.has(survivor.id)
|
||
|
|
|
||
|
|
return (
|
||
|
|
<button
|
||
|
|
key={survivor.id}
|
||
|
|
type="button"
|
||
|
|
onClick={() => toggle(survivor.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">
|
||
|
|
{survivor.nickname || displayPokemon.name}
|
||
|
|
</span>
|
||
|
|
{survivor.nickname && (
|
||
|
|
<span className="text-[10px] text-gray-400">
|
||
|
|
{displayPokemon.name}
|
||
|
|
</span>
|
||
|
|
)}
|
||
|
|
<span className="text-[10px] text-gray-400 mt-0.5">
|
||
|
|
{survivor.routeName}
|
||
|
|
</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}/{survivors.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>
|
||
|
|
)
|
||
|
|
}
|