import { Link, useParams } from 'react-router-dom' import { useGenlocke } from '../hooks/useGenlockes' import { usePokemonFamilies } from '../hooks/usePokemon' import { GenlockeGraveyard, GenlockeLineage, StatCard, RuleBadges } from '../components' import type { GenlockeLegDetail, RetiredPokemon, RunStatus } from '../types' import { useMemo, useState } from 'react' const statusColors: Record = { completed: 'bg-blue-500', active: 'bg-green-500', failed: 'bg-red-500', } const statusRing: Record = { completed: 'ring-accent-500', active: 'ring-green-500 animate-pulse', failed: 'ring-red-500', } const statusStyles: Record = { active: 'bg-green-100 text-green-800 dark:bg-green-900/40 dark:text-green-300', completed: 'bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300', failed: 'bg-red-100 text-red-800 dark:bg-red-900/40 dark:text-red-300', } function LegIndicator({ leg }: { leg: GenlockeLegDetail }) { const hasRun = leg.runId !== null const status = leg.runStatus as RunStatus | null const dot = status ? (
) : (
) const content = (
{dot} {leg.game.name} {status && {status}}
) if (hasRun) { return ( {content} ) } return content } function PokemonSprite({ pokemon }: { pokemon: RetiredPokemon }) { if (pokemon.spriteUrl) { return ( {pokemon.name} ) } return (
{pokemon.name[0]?.toUpperCase()}
) } export function GenlockeDetail() { const { genlockeId } = useParams<{ genlockeId: string }>() const id = Number(genlockeId) const { data: genlocke, isLoading, error } = useGenlocke(id) const { data: familiesData } = usePokemonFamilies() const [showGraveyard, setShowGraveyard] = useState(false) const [showLineage, setShowLineage] = useState(false) const activeLeg = useMemo(() => { if (!genlocke) return null return genlocke.legs.find((l) => l.runStatus === 'active') ?? null }, [genlocke]) // Group retired Pokemon by leg, showing only the "base" Pokemon per family const retiredByLeg = useMemo(() => { if (!genlocke || !familiesData) return [] const familyMap = new Map() for (const family of familiesData.families) { for (const id of family) { familyMap.set(id, family) } } return genlocke.legs .filter((leg) => leg.retiredPokemonIds && leg.retiredPokemonIds.length > 0) .map((leg) => { // Find base Pokemon (lowest ID) for each family in this leg's retired list const seen = new Set() const bases: number[] = [] for (const pid of leg.retiredPokemonIds!) { const family = familyMap.get(pid) const key = family ? family.join(',') : String(pid) if (!seen.has(key)) { seen.add(key) bases.push(family ? Math.min(...family) : pid) } } return { legOrder: leg.legOrder, gameName: leg.game.name, pokemonIds: bases.sort((a, b) => a - b), } }) }, [genlocke, familiesData]) if (isLoading) { return (
) } if (error || !genlocke) { return (
Failed to load genlocke. Please try again.
) } const survivalRate = genlocke.stats.totalEncounters > 0 ? Math.round( ((genlocke.stats.totalEncounters - genlocke.stats.totalDeaths) / genlocke.stats.totalEncounters) * 100 ) : 0 return (
{/* Header */}
← Back to Genlockes

{genlocke.name}

{genlocke.status}
{/* Progress Timeline */}

Progress

{genlocke.legs.map((leg, i) => (
{i < genlocke.legs.length - 1 && (
)}
))}
{/* Cumulative Stats */}

Cumulative Stats

{/* Configuration */}

Configuration

Genlocke Rules

{genlocke.genlockeRules.retireHoF ? ( Retire HoF Teams ) : ( No genlocke-specific rules enabled )}

Nuzlocke Rules

{/* Retired Families */} {genlocke.genlockeRules.retireHoF && retiredByLeg.length > 0 && (

Retired Families

{retiredByLeg.map((leg) => (

Leg {leg.legOrder} — {leg.gameName}

{leg.pokemonIds.map((pid) => { const pokemon = genlocke.retiredPokemon[pid] if (!pokemon) return null return })}
))}
)} {/* Quick Actions */}

Quick Actions

{activeLeg && ( Go to Active Leg (Leg {activeLeg.legOrder}) )}
{/* Graveyard */} {showGraveyard && (

Cumulative Graveyard

)} {/* Lineage */} {showLineage && (

Pokemon Lineages

)}
) }