From c3bbd365a9b78dee2f87271e134d0b652025c316 Mon Sep 17 00:00:00 2001 From: Julian Tabel Date: Sun, 8 Feb 2026 20:19:16 +0100 Subject: [PATCH] Replace free-text encounter method input with dropdown selector Use the predefined METHOD_ORDER/METHOD_CONFIG from EncounterMethodBadge to populate a select dropdown with all known encounter methods plus an "Other" option for custom values. Shows a colored badge preview on selection. Correctly handles editing encounters with non-standard methods. Co-Authored-By: Claude Opus 4.6 --- ...counter-method-input-in-route-encounter.md | 5 +- ...w9s--gauntlet-rule-option-for-genlockes.md | 24 ++++++++++ .../src/components/EncounterMethodBadge.tsx | 2 +- .../admin/RouteEncounterFormModal.tsx | 47 ++++++++++++++++--- 4 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 .beans/nuzlocke-tracker-8w9s--gauntlet-rule-option-for-genlockes.md diff --git a/.beans/nuzlocke-tracker-5o1v--improve-encounter-method-input-in-route-encounter.md b/.beans/nuzlocke-tracker-5o1v--improve-encounter-method-input-in-route-encounter.md index 010a164..ad9b6f7 100644 --- a/.beans/nuzlocke-tracker-5o1v--improve-encounter-method-input-in-route-encounter.md +++ b/.beans/nuzlocke-tracker-5o1v--improve-encounter-method-input-in-route-encounter.md @@ -1,10 +1,11 @@ --- # nuzlocke-tracker-5o1v title: Improve encounter method input in route encounter form -status: todo +status: completed type: feature +priority: normal created_at: 2026-02-08T19:06:10Z -updated_at: 2026-02-08T19:06:10Z +updated_at: 2026-02-08T19:17:14Z parent: nuzlocke-tracker-iu5b --- diff --git a/.beans/nuzlocke-tracker-8w9s--gauntlet-rule-option-for-genlockes.md b/.beans/nuzlocke-tracker-8w9s--gauntlet-rule-option-for-genlockes.md new file mode 100644 index 0000000..cb5be5c --- /dev/null +++ b/.beans/nuzlocke-tracker-8w9s--gauntlet-rule-option-for-genlockes.md @@ -0,0 +1,24 @@ +--- +# nuzlocke-tracker-8w9s +title: Gauntlet rule option for genlockes +status: draft +type: feature +created_at: 2026-02-08T19:15:43Z +updated_at: 2026-02-08T19:15:43Z +parent: nuzlocke-tracker-25mh +--- + +Add an optional **Gauntlet** rule for genlocke runs. When enabled, Pokemon that enter the Hall of Fame at the end of a leg are NOT transferred to the next game — instead, they (and their evolutionary families) are added to the dupe list for subsequent legs. + +## Behavior +- Toggled as an optional rule when creating/editing a genlocke +- When a leg is completed, surviving Hall of Fame Pokemon are marked as "dupes" for the next leg rather than being transferred as eggs/starters +- This means the player cannot catch anything in those evolutionary lines in future legs (standard dupe clause enforcement) +- The cumulative dupe list grows with each completed leg +- Effectively forces the player to use entirely new Pokemon each generation + +## Notes +- This is a variant of the standard genlocke format that increases difficulty +- The dupe list should track evolutionary families, not just the specific Pokemon (e.g., if Charizard is in the HoF, Charmander and Charmeleon are also duped) +- Should integrate with the existing dupe clause system already in the tracker +- Consider showing the cumulative gauntlet dupe list somewhere in the genlocke dashboard \ No newline at end of file diff --git a/frontend/src/components/EncounterMethodBadge.tsx b/frontend/src/components/EncounterMethodBadge.tsx index 28267ae..46c9340 100644 --- a/frontend/src/components/EncounterMethodBadge.tsx +++ b/frontend/src/components/EncounterMethodBadge.tsx @@ -1,4 +1,4 @@ -const METHOD_CONFIG: Record = { +export const METHOD_CONFIG: Record = { starter: { label: 'Starter', color: diff --git a/frontend/src/components/admin/RouteEncounterFormModal.tsx b/frontend/src/components/admin/RouteEncounterFormModal.tsx index 8c1695a..0281f59 100644 --- a/frontend/src/components/admin/RouteEncounterFormModal.tsx +++ b/frontend/src/components/admin/RouteEncounterFormModal.tsx @@ -1,6 +1,7 @@ import { type FormEvent, useState } from 'react' import { FormModal } from './FormModal' import { PokemonSelector } from './PokemonSelector' +import { METHOD_ORDER, METHOD_CONFIG, getMethodLabel } from '../EncounterMethodBadge' import type { RouteEncounterDetail, CreateRouteEncounterInput, UpdateRouteEncounterInput } from '../../types' interface RouteEncounterFormModalProps { @@ -21,7 +22,13 @@ export function RouteEncounterFormModal({ isDeleting, }: RouteEncounterFormModalProps) { const [pokemonId, setPokemonId] = useState(encounter?.pokemonId ?? 0) - const [encounterMethod, setEncounterMethod] = useState(encounter?.encounterMethod ?? '') + + const initialMethod = encounter?.encounterMethod ?? '' + const isKnownMethod = METHOD_ORDER.includes(initialMethod) + const [selectedMethod, setSelectedMethod] = useState(isKnownMethod ? initialMethod : initialMethod ? 'other' : '') + const [customMethod, setCustomMethod] = useState(isKnownMethod ? '' : initialMethod) + const encounterMethod = selectedMethod === 'other' ? customMethod : selectedMethod + const [encounterRate, setEncounterRate] = useState(String(encounter?.encounterRate ?? '')) const [minLevel, setMinLevel] = useState(String(encounter?.minLevel ?? '')) const [maxLevel, setMaxLevel] = useState(String(encounter?.maxLevel ?? '')) @@ -64,14 +71,40 @@ export function RouteEncounterFormModal({ )}
- setEncounterMethod(e.target.value)} - placeholder="e.g. Walking, Surfing, Fishing" + value={selectedMethod} + onChange={(e) => { + setSelectedMethod(e.target.value) + if (e.target.value !== 'other') setCustomMethod('') + }} className="w-full px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600" - /> + > + + {METHOD_ORDER.map((m) => ( + + ))} + + + {selectedMethod && selectedMethod !== 'other' && ( + + {getMethodLabel(selectedMethod)} + + )} + {selectedMethod === 'other' && ( + setCustomMethod(e.target.value)} + placeholder="Custom method name" + className="w-full mt-2 px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600" + /> + )}