componentize iv form
This commit is contained in:
parent
aaaec295a2
commit
44a734bcac
186
src/ts/app/components/PokemonExplorer/IvForm.tsx
Normal file
186
src/ts/app/components/PokemonExplorer/IvForm.tsx
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { IIndividualValues, IndividualValueKey } from './types';
|
||||||
|
|
||||||
|
import * as styles from './styles/IvForm.scss';
|
||||||
|
|
||||||
|
export interface IIvFormProps {
|
||||||
|
ivs : IIndividualValues;
|
||||||
|
placeholder : IIndividualValues;
|
||||||
|
|
||||||
|
handleChangeIndividualValue : (stat : IndividualValueKey, value : number | null) => void;
|
||||||
|
handleMaximizeLevel : () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
form : {
|
||||||
|
level : string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class IvForm extends React.Component<IIvFormProps, IState> {
|
||||||
|
|
||||||
|
private readonly MIN_LEVEL = 1;
|
||||||
|
private readonly MAX_LEVEL = 40;
|
||||||
|
private readonly MIN_IV = 0;
|
||||||
|
private readonly MAX_IV = 15;
|
||||||
|
|
||||||
|
private handleChangeHp : (event : React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
private handleChangeAtk : (event : React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
private handleChangeDef : (event : React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
|
||||||
|
constructor(props : IIvFormProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
form: {
|
||||||
|
level: '',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.handleChangeHp = this.handleChangeIvFactory('hp');
|
||||||
|
this.handleChangeAtk = this.handleChangeIvFactory('atk');
|
||||||
|
this.handleChangeDef = this.handleChangeIvFactory('def');
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const {
|
||||||
|
ivs,
|
||||||
|
placeholder,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const idIvLevelInput = 'iv-level-input';
|
||||||
|
const idIvHpInput = 'iv-hp-input';
|
||||||
|
const idIvAtkInput = 'iv-atk-input';
|
||||||
|
const idIvDefInput = 'iv-def-input';
|
||||||
|
|
||||||
|
const fieldCss = classNames(
|
||||||
|
'nes-field',
|
||||||
|
);
|
||||||
|
const inlineFieldCss = classNames(
|
||||||
|
fieldCss,
|
||||||
|
'is-inline',
|
||||||
|
styles.fieldRow,
|
||||||
|
);
|
||||||
|
const inputTextCss = classNames(
|
||||||
|
'nes-input',
|
||||||
|
styles.ivInput,
|
||||||
|
);
|
||||||
|
const inputTextLevelCss = classNames(
|
||||||
|
inputTextCss,
|
||||||
|
styles.levelInput,
|
||||||
|
);
|
||||||
|
const maxButtonCss = classNames(
|
||||||
|
'nes-btn',
|
||||||
|
{
|
||||||
|
'is-primary': ivs.ivHp !== null && ivs.ivAtk !== null && ivs.ivDef !== null,
|
||||||
|
'is-disabled': ivs.ivHp === null || ivs.ivAtk === null || ivs.ivDef === null,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const ivLevel = this.state.form.level !== '' ? parseInt(this.state.form.level, 10) : ivs.level;
|
||||||
|
const showPlaceholder = ivs.level === null && ivs.ivHp === null && ivs.ivAtk === null && ivs.ivDef === null;
|
||||||
|
|
||||||
|
return [(
|
||||||
|
<div key="iv-form-row-1" className={ inlineFieldCss }>
|
||||||
|
<label htmlFor={ idIvHpInput }>HP</label>
|
||||||
|
<input
|
||||||
|
name="hp"
|
||||||
|
type="number"
|
||||||
|
id={ idIvHpInput }
|
||||||
|
className={ inputTextCss }
|
||||||
|
min={ this.MIN_IV }
|
||||||
|
max={ this.MAX_IV }
|
||||||
|
maxLength={ 2 }
|
||||||
|
onChange={ this.handleChangeHp }
|
||||||
|
value={ ivs.ivHp !== null ? ivs.ivHp : '' }
|
||||||
|
placeholder={ showPlaceholder ? '' + placeholder.ivHp : '' }
|
||||||
|
/>
|
||||||
|
<label htmlFor={ idIvAtkInput }>ATK</label>
|
||||||
|
<input
|
||||||
|
name="atk"
|
||||||
|
type="number"
|
||||||
|
id={ idIvAtkInput }
|
||||||
|
className={ inputTextCss }
|
||||||
|
min={ this.MIN_IV }
|
||||||
|
max={ this.MAX_IV }
|
||||||
|
maxLength={ 2 }
|
||||||
|
onChange={ this.handleChangeAtk }
|
||||||
|
value={ ivs.ivAtk !== null ? ivs.ivAtk : '' }
|
||||||
|
placeholder={ showPlaceholder ? '' + placeholder.ivAtk : '' }
|
||||||
|
/>
|
||||||
|
<label htmlFor={ idIvDefInput }>DEF</label>
|
||||||
|
<input
|
||||||
|
name="def"
|
||||||
|
type="number"
|
||||||
|
id={ idIvDefInput }
|
||||||
|
className={ inputTextCss }
|
||||||
|
min={ this.MIN_IV }
|
||||||
|
max={ this.MAX_IV }
|
||||||
|
maxLength={ 2 }
|
||||||
|
onChange={ this.handleChangeDef }
|
||||||
|
value={ ivs.ivDef !== null ? ivs.ivDef : '' }
|
||||||
|
placeholder={ showPlaceholder ? '' + placeholder.ivDef : '' }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
), (
|
||||||
|
<div key="iv-form-row-2" className={ inlineFieldCss }>
|
||||||
|
<div className={ inlineFieldCss }>
|
||||||
|
<label htmlFor={ idIvLevelInput }>Lv</label>
|
||||||
|
<input
|
||||||
|
name="level"
|
||||||
|
type="number"
|
||||||
|
id={ idIvLevelInput }
|
||||||
|
className={ inputTextLevelCss }
|
||||||
|
min={ this.MIN_LEVEL }
|
||||||
|
max={ this.MAX_LEVEL }
|
||||||
|
step={ 0.5 }
|
||||||
|
onChange={ this.handleChangeLevel }
|
||||||
|
value={ ivLevel !== null ? ivLevel : '' }
|
||||||
|
placeholder={ showPlaceholder ? '' + placeholder.level : '' }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={ maxButtonCss }
|
||||||
|
disabled={ ivs.ivHp === null || ivs.ivAtk === null || ivs.ivDef === null }
|
||||||
|
onClick={ this.handleClickMaximizeLevel }
|
||||||
|
>
|
||||||
|
MAX LEAGUE Lv
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly handleChangeLevel = (event : React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const raw = event.currentTarget.value;
|
||||||
|
const value = parseFloat(raw);
|
||||||
|
|
||||||
|
this.setState({ form: { level: '' } });
|
||||||
|
if (raw === '' + value && value >= this.MIN_LEVEL && value <= this.MAX_LEVEL && value % 0.5 === 0) {
|
||||||
|
this.props.handleChangeIndividualValue('level', value);
|
||||||
|
} else if (raw === '') {
|
||||||
|
this.props.handleChangeIndividualValue('level', null);
|
||||||
|
} else if (raw.charAt(raw.length) === '.') {
|
||||||
|
this.setState({ form: { level: raw } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly handleClickMaximizeLevel = () => {
|
||||||
|
this.props.handleMaximizeLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly handleChangeIvFactory = (type : IndividualValueKey) => {
|
||||||
|
return (event : React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const raw = event.currentTarget.value;
|
||||||
|
const value = parseInt(raw, 10);
|
||||||
|
if (raw === '' + value && value >= this.MIN_IV && value <= this.MAX_IV) {
|
||||||
|
this.props.handleChangeIndividualValue(type, value);
|
||||||
|
} else if (raw === '') {
|
||||||
|
this.props.handleChangeIndividualValue(type, null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -57,15 +57,15 @@ export class LeagueStatsList extends React.Component<ILeagueStatsListProps, ISta
|
|||||||
if (this.listRef.current !== null) {
|
if (this.listRef.current !== null) {
|
||||||
this.listRef.current.scrollToItem(0);
|
this.listRef.current.scrollToItem(0);
|
||||||
}
|
}
|
||||||
} else if (activeIvs.level !== null && activeIvs.hp !== null && activeIvs.atk !== null && activeIvs.def !== null) {
|
} else if (activeIvs.level !== null && activeIvs.ivHp !== null && activeIvs.ivAtk !== null && activeIvs.ivDef !== null) {
|
||||||
let activeIndex = this.state.activeIndex;
|
let activeIndex = this.state.activeIndex;
|
||||||
if (activeIndex === -1) {
|
if (activeIndex === -1) {
|
||||||
// there is no current index, wich means the user is entering in the IVs by hand
|
// there is no current index, wich means the user is entering in the IVs by hand
|
||||||
// now we will look through the list to see if we can find a match
|
// now we will look through the list to see if we can find a match
|
||||||
this.props.leagueStatsList.some((stats, index) => {
|
this.props.leagueStatsList.some((stats, index) => {
|
||||||
if (activeIvs.hp === stats.ivHp &&
|
if (activeIvs.ivHp === stats.ivHp &&
|
||||||
activeIvs.atk === stats.ivAtk &&
|
activeIvs.ivAtk === stats.ivAtk &&
|
||||||
activeIvs.def === stats.ivDef
|
activeIvs.ivDef === stats.ivDef
|
||||||
) {
|
) {
|
||||||
this.setState({ activeIndex: index });
|
this.setState({ activeIndex: index });
|
||||||
activeIndex = index;
|
activeIndex = index;
|
||||||
@ -77,7 +77,7 @@ export class LeagueStatsList extends React.Component<ILeagueStatsListProps, ISta
|
|||||||
|
|
||||||
if (activeIndex > -1) {
|
if (activeIndex > -1) {
|
||||||
const stateStats = this.props.leagueStatsList[activeIndex];
|
const stateStats = this.props.leagueStatsList[activeIndex];
|
||||||
if (activeIvs.hp === stateStats.ivHp && activeIvs.atk === stateStats.ivAtk && activeIvs.def === stateStats.ivDef) {
|
if (activeIvs.ivHp === stateStats.ivHp && activeIvs.ivAtk === stateStats.ivAtk && activeIvs.ivDef === stateStats.ivDef) {
|
||||||
// the current IVs belong to the stats at the active index, so scroll to active stats
|
// the current IVs belong to the stats at the active index, so scroll to active stats
|
||||||
if (this.listRef.current !== null) {
|
if (this.listRef.current !== null) {
|
||||||
this.listRef.current.scrollToItem(activeIndex, 'center');
|
this.listRef.current.scrollToItem(activeIndex, 'center');
|
||||||
@ -142,9 +142,9 @@ export class LeagueStatsList extends React.Component<ILeagueStatsListProps, ISta
|
|||||||
styles.listItem,
|
styles.listItem,
|
||||||
{
|
{
|
||||||
active: activeIvs.level === stats.level &&
|
active: activeIvs.level === stats.level &&
|
||||||
activeIvs.hp === stats.ivHp &&
|
activeIvs.ivHp === stats.ivHp &&
|
||||||
activeIvs.atk === stats.ivAtk &&
|
activeIvs.ivAtk === stats.ivAtk &&
|
||||||
activeIvs.def === stats.ivDef,
|
activeIvs.ivDef === stats.ivDef,
|
||||||
highlight: this.state.activeIndex === index,
|
highlight: this.state.activeIndex === index,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -4,13 +4,14 @@ import React from 'react';
|
|||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { IBestWorstStats, ILeaguePokemon, League } from 'app/models/League';
|
import { IBestWorstStats, ILeaguePokemon, League, MaxCpByLeague } from 'app/models/League';
|
||||||
import { Grade, IStats, } from 'app/models/Pokemon';
|
import { Grade, IStats, } from 'app/models/Pokemon';
|
||||||
import { calculateCp, calculateStatAtLevel } from 'app/utils/calculator';
|
import { calculateCp, calculateStatAtLevel } from 'app/utils/calculator';
|
||||||
import { formatDexNumber, formatForm, formatType, Forms } from 'app/utils/formatter';
|
import { formatDexNumber, formatForm, formatType, Forms } from 'app/utils/formatter';
|
||||||
|
|
||||||
import { IIndividualValues, IndividualValueKey } from './types';
|
import { IIndividualValues, IndividualValueKey } from './types';
|
||||||
|
|
||||||
|
import { IvForm } from './IvForm';
|
||||||
import { LeagueSelector } from './LeagueSelector';
|
import { LeagueSelector } from './LeagueSelector';
|
||||||
import { LeagueStatsList } from './LeagueStatsList';
|
import { LeagueStatsList } from './LeagueStatsList';
|
||||||
import { StatDisplay } from './StatDisplay';
|
import { StatDisplay } from './StatDisplay';
|
||||||
@ -58,15 +59,6 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly MIN_LEVEL = 1;
|
|
||||||
private readonly MAX_LEVEL = 40;
|
|
||||||
private readonly MIN_IV = 0;
|
|
||||||
private readonly MAX_IV = 15;
|
|
||||||
|
|
||||||
private handleChangeHp : (event : React.ChangeEvent<HTMLInputElement>) => void;
|
|
||||||
private handleChangeAtk : (event : React.ChangeEvent<HTMLInputElement>) => void;
|
|
||||||
private handleChangeDef : (event : React.ChangeEvent<HTMLInputElement>) => void;
|
|
||||||
|
|
||||||
constructor(props : IPokemonExplorerProps) {
|
constructor(props : IPokemonExplorerProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@ -75,51 +67,40 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
|||||||
level: '',
|
level: '',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.handleChangeHp = this.handleChangeIvFactory('hp');
|
|
||||||
this.handleChangeAtk = this.handleChangeIvFactory('atk');
|
|
||||||
this.handleChangeDef = this.handleChangeIvFactory('def');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const {
|
const {
|
||||||
activeLeague,
|
activeLeague,
|
||||||
individualValues,
|
individualValues,
|
||||||
leaguePokemon
|
leaguePokemon,
|
||||||
|
handleChangeIndividualValue,
|
||||||
|
handleMaximizeLevel,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
let rankedPokemon : IStats | null = null;
|
let rankedPokemon : IStats | null = null;
|
||||||
let placeholderLevel = '';
|
|
||||||
let placeholderHp = '';
|
|
||||||
let placeholderAtk = '';
|
|
||||||
let placeholderDef = '';
|
|
||||||
|
|
||||||
const dex = formatDexNumber(leaguePokemon.dex);
|
const dex = formatDexNumber(leaguePokemon.dex);
|
||||||
const individualValueLevel = this.state.form.level !== '' ? this.state.form.level : individualValues.level;
|
|
||||||
|
|
||||||
// default to first pokemon (should be S tier)
|
// default to first pokemon (should be S tier)
|
||||||
if (individualValueLevel === null &&
|
if (individualValues.level === null &&
|
||||||
individualValues.hp === null &&
|
individualValues.ivHp === null &&
|
||||||
individualValues.atk === null &&
|
individualValues.ivAtk === null &&
|
||||||
individualValues.def === null
|
individualValues.ivDef === null
|
||||||
) {
|
) {
|
||||||
rankedPokemon = leaguePokemon.pvp[activeLeague][0];
|
rankedPokemon = leaguePokemon.pvp[activeLeague][0];
|
||||||
placeholderLevel = '' + rankedPokemon.level;
|
|
||||||
placeholderHp = '' + rankedPokemon.ivHp;
|
|
||||||
placeholderAtk = '' + rankedPokemon.ivAtk;
|
|
||||||
placeholderDef = '' + rankedPokemon.ivDef;
|
|
||||||
|
|
||||||
// a full spec'd pokemon has been entered
|
// a full spec'd pokemon has been entered
|
||||||
} else if (individualValueLevel !== null && typeof individualValueLevel === 'number' &&
|
} else if (individualValues.level !== null &&
|
||||||
individualValues.hp !== null &&
|
individualValues.ivHp !== null &&
|
||||||
individualValues.atk !== null &&
|
individualValues.ivAtk !== null &&
|
||||||
individualValues.def !== null
|
individualValues.ivDef !== null
|
||||||
) {
|
) {
|
||||||
leaguePokemon.pvp[activeLeague].some((stats) => {
|
leaguePokemon.pvp[activeLeague].some((stats) => {
|
||||||
if (individualValueLevel === stats.level &&
|
if (individualValues.level === stats.level &&
|
||||||
individualValues.hp === stats.ivHp &&
|
individualValues.ivHp === stats.ivHp &&
|
||||||
individualValues.atk === stats.ivAtk &&
|
individualValues.ivAtk === stats.ivAtk &&
|
||||||
individualValues.def === stats.ivDef
|
individualValues.ivDef === stats.ivDef
|
||||||
) {
|
) {
|
||||||
rankedPokemon = stats;
|
rankedPokemon = stats;
|
||||||
return true;
|
return true;
|
||||||
@ -130,14 +111,14 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
|||||||
// we don't have the data for this terrible mon
|
// we don't have the data for this terrible mon
|
||||||
if (rankedPokemon === null) {
|
if (rankedPokemon === null) {
|
||||||
rankedPokemon = {
|
rankedPokemon = {
|
||||||
cp: calculateCp(leaguePokemon.stats, individualValueLevel, individualValues.hp, individualValues.atk, individualValues.def),
|
cp: calculateCp(leaguePokemon.stats, individualValues.level, individualValues.ivHp, individualValues.ivAtk, individualValues.ivDef),
|
||||||
level: individualValueLevel,
|
level: individualValues.level,
|
||||||
ivHp: individualValues.hp,
|
ivHp: individualValues.ivHp,
|
||||||
ivAtk: individualValues.atk,
|
ivAtk: individualValues.ivAtk,
|
||||||
ivDef: individualValues.def,
|
ivDef: individualValues.ivDef,
|
||||||
hp: calculateStatAtLevel(individualValueLevel, leaguePokemon.stats.baseStamina, individualValues.hp),
|
hp: calculateStatAtLevel(individualValues.level, leaguePokemon.stats.baseStamina, individualValues.ivHp),
|
||||||
atk: calculateStatAtLevel(individualValueLevel, leaguePokemon.stats.baseAttack, individualValues.atk),
|
atk: calculateStatAtLevel(individualValues.level, leaguePokemon.stats.baseAttack, individualValues.ivAtk),
|
||||||
def: calculateStatAtLevel(individualValueLevel, leaguePokemon.stats.baseDefense, individualValues.def),
|
def: calculateStatAtLevel(individualValues.level, leaguePokemon.stats.baseDefense, individualValues.ivDef),
|
||||||
total: 0,
|
total: 0,
|
||||||
speciesGrade: Grade.F,
|
speciesGrade: Grade.F,
|
||||||
metaGrade: Grade.F,
|
metaGrade: Grade.F,
|
||||||
@ -157,10 +138,6 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
|||||||
defenseStatRank,
|
defenseStatRank,
|
||||||
} = PokemonExplorer.calculateStatRanks(rankedPokemon, leaguePokemon.statMax[activeLeague]);
|
} = PokemonExplorer.calculateStatRanks(rankedPokemon, leaguePokemon.statMax[activeLeague]);
|
||||||
|
|
||||||
const idIvLevelInput = 'iv-level-input';
|
|
||||||
const idIvHpInput = 'iv-hp-input';
|
|
||||||
const idIvAtkInput = 'iv-atk-input';
|
|
||||||
const idIvDefInput = 'iv-def-input';
|
|
||||||
const containerCss = classNames(
|
const containerCss = classNames(
|
||||||
'nes-container',
|
'nes-container',
|
||||||
'with-title',
|
'with-title',
|
||||||
@ -184,22 +161,6 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
|||||||
containerCss,
|
containerCss,
|
||||||
'form',
|
'form',
|
||||||
);
|
);
|
||||||
const fieldCss = classNames(
|
|
||||||
'nes-field',
|
|
||||||
);
|
|
||||||
const inlineFieldCss = classNames(
|
|
||||||
fieldCss,
|
|
||||||
'is-inline',
|
|
||||||
styles.fieldRow,
|
|
||||||
);
|
|
||||||
const inputTextCss = classNames(
|
|
||||||
'nes-input',
|
|
||||||
styles.ivInput,
|
|
||||||
);
|
|
||||||
const inputTextLevelCss = classNames(
|
|
||||||
inputTextCss,
|
|
||||||
styles.levelInput,
|
|
||||||
);
|
|
||||||
const leaugeRankCss = classNames(
|
const leaugeRankCss = classNames(
|
||||||
styles.leaguePokemonRank,
|
styles.leaguePokemonRank,
|
||||||
containerCss,
|
containerCss,
|
||||||
@ -207,13 +168,6 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
|||||||
'with-title': false
|
'with-title': false
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const maxButtonCss = classNames(
|
|
||||||
'nes-btn',
|
|
||||||
{
|
|
||||||
'is-primary': individualValues.hp !== null && individualValues.atk !== null && individualValues.def !== null,
|
|
||||||
'is-disabled': individualValues.hp === null || individualValues.atk === null || individualValues.def === null,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const pokemonIconCss = classNames(
|
const pokemonIconCss = classNames(
|
||||||
`pokemon-${dex}`,
|
`pokemon-${dex}`,
|
||||||
@ -311,78 +265,23 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
|||||||
/>
|
/>
|
||||||
<section className={ formContainerCss }>
|
<section className={ formContainerCss }>
|
||||||
<h5 className={ containerTitleCss }>IVs</h5>
|
<h5 className={ containerTitleCss }>IVs</h5>
|
||||||
<div className={ inlineFieldCss }>
|
<IvForm
|
||||||
<label htmlFor={ idIvHpInput }>HP</label>
|
ivs={ individualValues }
|
||||||
<input
|
placeholder={ leaguePokemon.pvp[activeLeague][0] }
|
||||||
name="hp"
|
handleChangeIndividualValue={ handleChangeIndividualValue }
|
||||||
type="number"
|
handleMaximizeLevel={ handleMaximizeLevel }
|
||||||
id={ idIvHpInput }
|
|
||||||
className={ inputTextCss }
|
|
||||||
min={ this.MIN_IV }
|
|
||||||
max={ this.MAX_IV }
|
|
||||||
maxLength={ 2 }
|
|
||||||
onChange={ this.handleChangeHp }
|
|
||||||
value={ individualValues.hp !== null ? individualValues.hp : '' }
|
|
||||||
placeholder={ placeholderHp }
|
|
||||||
/>
|
/>
|
||||||
<label htmlFor={ idIvAtkInput }>ATK</label>
|
|
||||||
<input
|
|
||||||
name="atk"
|
|
||||||
type="number"
|
|
||||||
id={ idIvAtkInput }
|
|
||||||
className={ inputTextCss }
|
|
||||||
min={ this.MIN_IV }
|
|
||||||
max={ this.MAX_IV }
|
|
||||||
maxLength={ 2 }
|
|
||||||
onChange={ this.handleChangeAtk }
|
|
||||||
value={ individualValues.atk !== null ? individualValues.atk : '' }
|
|
||||||
placeholder={ placeholderAtk }
|
|
||||||
/>
|
|
||||||
<label htmlFor={ idIvDefInput }>DEF</label>
|
|
||||||
<input
|
|
||||||
name="def"
|
|
||||||
type="number"
|
|
||||||
id={ idIvDefInput }
|
|
||||||
className={ inputTextCss }
|
|
||||||
min={ this.MIN_IV }
|
|
||||||
max={ this.MAX_IV }
|
|
||||||
maxLength={ 2 }
|
|
||||||
onChange={ this.handleChangeDef }
|
|
||||||
value={ individualValues.def !== null ? individualValues.def : '' }
|
|
||||||
placeholder={ placeholderDef }
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={ inlineFieldCss }>
|
|
||||||
<div className={ inlineFieldCss }>
|
|
||||||
<label htmlFor={ idIvLevelInput }>Lv</label>
|
|
||||||
<input
|
|
||||||
name="level"
|
|
||||||
type="number"
|
|
||||||
id={ idIvLevelInput }
|
|
||||||
className={ inputTextLevelCss }
|
|
||||||
min={ this.MIN_LEVEL }
|
|
||||||
max={ this.MAX_LEVEL }
|
|
||||||
step={ 0.5 }
|
|
||||||
onChange={ this.handleChangeLevel }
|
|
||||||
value={ individualValueLevel !== null ? individualValueLevel : '' }
|
|
||||||
placeholder={ placeholderLevel }
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={ maxButtonCss }
|
|
||||||
disabled={ individualValues.hp === null || individualValues.atk === null || individualValues.def === null }
|
|
||||||
onClick={ this.handleClickMaximizeLevel }
|
|
||||||
>
|
|
||||||
MAX LEAGUE Lv
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
<section className={ leaugeRankCss }>
|
<section className={ leaugeRankCss }>
|
||||||
<h5 className={ containerTitleCss }>Rank</h5>
|
<h5 className={ containerTitleCss }>Rank</h5>
|
||||||
<div className={ styles.pokemonInfoWraper }>
|
<div className={ styles.pokemonInfoWraper }>
|
||||||
<div className={ styles.pokemonInfoLeftColumn }>
|
<div className={ styles.pokemonInfoLeftColumn }>
|
||||||
|
{ rankedPokemon === null || rankedPokemon.cp > MaxCpByLeague[activeLeague] &&
|
||||||
|
<div><h1 className={ styles.pokemonRankValue }>N/A</h1></div>
|
||||||
|
}
|
||||||
|
{ rankedPokemon !== null && rankedPokemon.cp <= MaxCpByLeague[activeLeague] &&
|
||||||
<div><h1 className={ styles.pokemonRankValue }>{ rankedGrade }</h1> Rank</div>
|
<div><h1 className={ styles.pokemonRankValue }>{ rankedGrade }</h1> Rank</div>
|
||||||
|
}
|
||||||
<div>CP <h1 className={ styles.pokemonRankValue }>{ rankedCp }</h1></div>
|
<div>CP <h1 className={ styles.pokemonRankValue }>{ rankedCp }</h1></div>
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.pokemonInfoRightColumn }>
|
<div className={ styles.pokemonInfoRightColumn }>
|
||||||
@ -416,36 +315,6 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly handleChangeLevel = (event : React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const raw = event.currentTarget.value;
|
|
||||||
const value = parseFloat(raw);
|
|
||||||
|
|
||||||
this.setState({ form: { level: '' } });
|
|
||||||
if (raw === '' + value && value >= this.MIN_LEVEL && value <= this.MAX_LEVEL && value % 0.5 === 0) {
|
|
||||||
this.props.handleChangeIndividualValue('level', value);
|
|
||||||
} else if (raw === '') {
|
|
||||||
this.props.handleChangeIndividualValue('level', null);
|
|
||||||
} else if (raw.charAt(raw.length) === '.') {
|
|
||||||
this.setState({ form: { level: raw } });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly handleClickMaximizeLevel = () => {
|
|
||||||
this.props.handleMaximizeLevel();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly handleChangeIvFactory = (type : IndividualValueKey) => {
|
|
||||||
return (event : React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const raw = event.currentTarget.value;
|
|
||||||
const value = parseInt(raw, 10);
|
|
||||||
if (raw === '' + value && value >= this.MIN_IV && value <= this.MAX_IV) {
|
|
||||||
this.props.handleChangeIndividualValue(type, value);
|
|
||||||
} else if (raw === '') {
|
|
||||||
this.props.handleChangeIndividualValue(type, null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly handleActivateLeagueStats = (stats : IStats) => {
|
private readonly handleActivateLeagueStats = (stats : IStats) => {
|
||||||
const { handleChangeIndividualValue } = this.props;
|
const { handleChangeIndividualValue } = this.props;
|
||||||
|
|
||||||
|
|||||||
@ -16,11 +16,11 @@ export const setLeaguePokemon = (leaguePokemon : ILeaguePokemon | null) => actio
|
|||||||
|
|
||||||
export const setIvLevel = (level : number | null) => action(PokemonExplorerActionTypes.SET_IV_LEVEL, { level });
|
export const setIvLevel = (level : number | null) => action(PokemonExplorerActionTypes.SET_IV_LEVEL, { level });
|
||||||
|
|
||||||
export const setIvHp = (hp : number | null) => action(PokemonExplorerActionTypes.SET_IV_HP, { hp });
|
export const setIvHp = (ivHp : number | null) => action(PokemonExplorerActionTypes.SET_IV_HP, { ivHp });
|
||||||
|
|
||||||
export const setIvAtk = (atk : number | null) => action(PokemonExplorerActionTypes.SET_IV_ATK, { atk });
|
export const setIvAtk = (ivAtk : number | null) => action(PokemonExplorerActionTypes.SET_IV_ATK, { ivAtk });
|
||||||
|
|
||||||
export const setIvDef = (def : number | null) => action(PokemonExplorerActionTypes.SET_IV_DEF, { def });
|
export const setIvDef = (ivDef : number | null) => action(PokemonExplorerActionTypes.SET_IV_DEF, { ivDef });
|
||||||
|
|
||||||
export const setActiveLeague = (league : League) => action(PokemonExplorerActionTypes.SET_ACTIVE_LEAGUE, { league });
|
export const setActiveLeague = (league : League) => action(PokemonExplorerActionTypes.SET_ACTIVE_LEAGUE, { league });
|
||||||
|
|
||||||
@ -37,17 +37,17 @@ export const maximizeLevel = (
|
|||||||
return async (dispatch, getState, extraArguments) => {
|
return async (dispatch, getState, extraArguments) => {
|
||||||
const pokemonExplorerState = getState().pokemonExplorerState;
|
const pokemonExplorerState = getState().pokemonExplorerState;
|
||||||
const {
|
const {
|
||||||
hp,
|
ivHp,
|
||||||
atk,
|
ivAtk,
|
||||||
def,
|
ivDef,
|
||||||
} = pokemonExplorerState.individualValues;
|
} = pokemonExplorerState.individualValues;
|
||||||
|
|
||||||
if (pokemonExplorerState.leaguePokemon !== null) {
|
if (pokemonExplorerState.leaguePokemon !== null) {
|
||||||
const pokemonLeagueValues = pokemonExplorerState.leaguePokemon.pvp[pokemonExplorerState.league];
|
const pokemonLeagueValues = pokemonExplorerState.leaguePokemon.pvp[pokemonExplorerState.league];
|
||||||
const statsSet = pokemonLeagueValues.some((stats) => {
|
const statsSet = pokemonLeagueValues.some((stats) => {
|
||||||
if (((hp === null) || (stats.ivHp === hp)) &&
|
if (((ivHp === null) || (stats.ivHp === ivHp)) &&
|
||||||
((atk === null) || (stats.ivAtk === atk)) &&
|
((ivAtk === null) || (stats.ivAtk === ivAtk)) &&
|
||||||
((def === null) || (stats.ivDef === def))
|
((ivDef === null) || (stats.ivDef === ivDef))
|
||||||
) {
|
) {
|
||||||
dispatch(setIvHp(stats.ivHp));
|
dispatch(setIvHp(stats.ivHp));
|
||||||
dispatch(setIvAtk(stats.ivAtk));
|
dispatch(setIvAtk(stats.ivAtk));
|
||||||
@ -57,8 +57,8 @@ export const maximizeLevel = (
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
if (!statsSet && hp !== null && atk !== null && def !== null) {
|
if (!statsSet && ivHp !== null && ivAtk !== null && ivDef !== null) {
|
||||||
dispatch(setIvLevel(calculateMaxLevelForLeague(pokemonExplorerState.leaguePokemon.stats, hp, atk, def, pokemonExplorerState.league)));
|
dispatch(setIvLevel(calculateMaxLevelForLeague(pokemonExplorerState.leaguePokemon.stats, ivHp, ivAtk, ivDef, pokemonExplorerState.league)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -14,9 +14,9 @@ export const initialState : IPokemonExplorerState = {
|
|||||||
},
|
},
|
||||||
individualValues: {
|
individualValues: {
|
||||||
level: null,
|
level: null,
|
||||||
hp: null,
|
ivHp: null,
|
||||||
atk: null,
|
ivAtk: null,
|
||||||
def: null,
|
ivDef: null,
|
||||||
},
|
},
|
||||||
league: 'great',
|
league: 'great',
|
||||||
};
|
};
|
||||||
@ -65,7 +65,7 @@ const reduceSetIvHp = (
|
|||||||
...state,
|
...state,
|
||||||
individualValues: {
|
individualValues: {
|
||||||
...state.individualValues,
|
...state.individualValues,
|
||||||
hp: action.payload.hp,
|
ivHp: action.payload.ivHp,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ const reduceSetIvAtk = (
|
|||||||
...state,
|
...state,
|
||||||
individualValues: {
|
individualValues: {
|
||||||
...state.individualValues,
|
...state.individualValues,
|
||||||
atk: action.payload.atk,
|
ivAtk: action.payload.ivAtk,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ const reduceSetIvDef = (
|
|||||||
...state,
|
...state,
|
||||||
individualValues: {
|
individualValues: {
|
||||||
...state.individualValues,
|
...state.individualValues,
|
||||||
def: action.payload.def,
|
ivDef: action.payload.ivDef,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
22
src/ts/app/components/PokemonExplorer/styles/IvForm.scss
Normal file
22
src/ts/app/components/PokemonExplorer/styles/IvForm.scss
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
:global(.nes-field.is-inline) .ivInput {
|
||||||
|
width: 4.25em;
|
||||||
|
padding-left: 0.7em;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
|
||||||
|
&.levelInput {
|
||||||
|
width: 6.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.nes-field.is-inline).fieldRow {
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
label {
|
||||||
|
flex-grow: 0;
|
||||||
|
margin-left: 1em;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/ts/app/components/PokemonExplorer/styles/IvForm.scss.d.ts
vendored
Normal file
5
src/ts/app/components/PokemonExplorer/styles/IvForm.scss.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// This file is automatically generated.
|
||||||
|
// Please do not change this file!
|
||||||
|
export const fieldRow: string;
|
||||||
|
export const ivInput: string;
|
||||||
|
export const levelInput: string;
|
||||||
@ -106,26 +106,3 @@
|
|||||||
align-items: start;
|
align-items: start;
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.nes-field.is-inline) .ivInput {
|
|
||||||
width: 4.25em;
|
|
||||||
padding-left: 0.7em;
|
|
||||||
padding-right: 0.5em;
|
|
||||||
|
|
||||||
&.levelInput {
|
|
||||||
width: 6.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.nes-field.is-inline).fieldRow {
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
label {
|
|
||||||
flex-grow: 0;
|
|
||||||
margin-left: 1em;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
// This file is automatically generated.
|
// This file is automatically generated.
|
||||||
// Please do not change this file!
|
// Please do not change this file!
|
||||||
export const dexHeader: string;
|
export const dexHeader: string;
|
||||||
export const fieldRow: string;
|
|
||||||
export const formHeader: string;
|
export const formHeader: string;
|
||||||
export const ivInput: string;
|
|
||||||
export const leaguePokemonRank: string;
|
export const leaguePokemonRank: string;
|
||||||
export const levelInput: string;
|
|
||||||
export const pokemonBaseStats: string;
|
export const pokemonBaseStats: string;
|
||||||
export const pokemonInfoLeftColumn: string;
|
export const pokemonInfoLeftColumn: string;
|
||||||
export const pokemonInfoRightColumn: string;
|
export const pokemonInfoRightColumn: string;
|
||||||
|
|||||||
@ -4,9 +4,9 @@ import { IMaxStats } from 'app/models/Pokemon';
|
|||||||
export type IndividualValueKey = 'level' | 'hp' | 'atk' | 'def';
|
export type IndividualValueKey = 'level' | 'hp' | 'atk' | 'def';
|
||||||
export interface IIndividualValues {
|
export interface IIndividualValues {
|
||||||
level : number | null;
|
level : number | null;
|
||||||
hp : number | null;
|
ivHp : number | null;
|
||||||
atk : number | null;
|
ivAtk : number | null;
|
||||||
def : number | null;
|
ivDef : number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPokemonExplorerState {
|
export interface IPokemonExplorerState {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user