split pokemon explorer from pokemon app

This commit is contained in:
Jeff Colombo 2019-03-11 00:43:22 -04:00
parent 7cd14f2b58
commit dd37703417
15 changed files with 1453 additions and 947 deletions

126
dist/app.css vendored
View File

@ -440,69 +440,6 @@
align-items: start;
align-self: stretch; }
.PokemonSelectList__wrapper__2LQMY {
font-size: 0.8rem;
width: 20em;
display: flex;
flex-flow: column nowrap;
margin: 0 1.5em 0 auto;
position: relative; }
.PokemonSelectList__wrapper__2LQMY .PokemonSelectList__listWrapper__bBtO6 {
flex: 1 1 auto;
display: flex;
padding: 0;
overflow: hidden;
height: 340px;
position: absolute;
top: 100%;
left: 0;
right: 0;
z-index: 2; }
.PokemonSelectList__wrapper__2LQMY .PokemonSelectList__listWrapper__bBtO6 > * {
width: 100%; }
.PokemonSelectList__wrapper__2LQMY .PokemonSelectList__listWrapper__bBtO6.PokemonSelectList__emptyList__1vgpK .PokemonSelectList__emptyState__3sBmb {
align-self: center;
text-align: center; }
.PokemonSelectList__wrapper__2LQMY .PokemonSelectList__listWrapper__bBtO6.PokemonSelectList__emptyList__1vgpK .PokemonSelectList__emptyState__3sBmb > *:first-child {
margin: 1em auto; }
.PokemonSelectList__wrapper__2LQMY a {
color: inherit;
text-decoration: none;
padding: 5px 1em 5px 2em;
justify-content: flex-end;
align-content: space-around;
flex-wrap: wrap;
display: flex; }
.PokemonSelectList__wrapper__2LQMY a .PokemonSelectList__menuIcon__1I2_T {
margin: -4px 0 0 0.5em;
opacity: 0.5; }
.PokemonSelectList__wrapper__2LQMY a.active .PokemonSelectList__menuIcon__1I2_T {
opacity: 1; }
.PokemonSelectList__filterWrapper__1d1Wl {
position: relative;
margin: 0.1em; }
.PokemonSelectList__filterWrapper__1d1Wl .close {
position: absolute;
top: 1em;
right: 1em; }
.PokemonSelectList__filterInput__1z_s2 {
margin-left: 0;
margin-right: 0;
padding-right: 3em; }
.PokemonSelectList__dex__1QHut,
.PokemonSelectList__form__VIw8Q {
font-size: 0.8em;
text-transform: capitalize; }
.PokemonSelectList__dex__1QHut {
margin-left: auto; }
.PokemonSelectList__form__VIw8Q {
flex: 0 1 100%; }
.TypeEffectiveDisplay__multiplierWrapper__1E9zx {
position: relative;
z-index: 0;
@ -567,5 +504,68 @@
flex-basis: unset;
width: 6.75rem; }
.PokemonSelectList__wrapper__2LQMY {
font-size: 0.8rem;
width: 20em;
display: flex;
flex-flow: column nowrap;
margin: 0 1.5em 0 auto;
position: relative; }
.PokemonSelectList__wrapper__2LQMY .PokemonSelectList__listWrapper__bBtO6 {
flex: 1 1 auto;
display: flex;
padding: 0;
overflow: hidden;
height: 340px;
position: absolute;
top: 100%;
left: 0;
right: 0;
z-index: 2; }
.PokemonSelectList__wrapper__2LQMY .PokemonSelectList__listWrapper__bBtO6 > * {
width: 100%; }
.PokemonSelectList__wrapper__2LQMY .PokemonSelectList__listWrapper__bBtO6.PokemonSelectList__emptyList__1vgpK .PokemonSelectList__emptyState__3sBmb {
align-self: center;
text-align: center; }
.PokemonSelectList__wrapper__2LQMY .PokemonSelectList__listWrapper__bBtO6.PokemonSelectList__emptyList__1vgpK .PokemonSelectList__emptyState__3sBmb > *:first-child {
margin: 1em auto; }
.PokemonSelectList__wrapper__2LQMY a {
color: inherit;
text-decoration: none;
padding: 5px 1em 5px 2em;
justify-content: flex-end;
align-content: space-around;
flex-wrap: wrap;
display: flex; }
.PokemonSelectList__wrapper__2LQMY a .PokemonSelectList__menuIcon__1I2_T {
margin: -4px 0 0 0.5em;
opacity: 0.5; }
.PokemonSelectList__wrapper__2LQMY a.active .PokemonSelectList__menuIcon__1I2_T {
opacity: 1; }
.PokemonSelectList__filterWrapper__1d1Wl {
position: relative;
margin: 0.1em; }
.PokemonSelectList__filterWrapper__1d1Wl .close {
position: absolute;
top: 1em;
right: 1em; }
.PokemonSelectList__filterInput__1z_s2 {
margin-left: 0;
margin-right: 0;
padding-right: 3em; }
.PokemonSelectList__dex__1QHut,
.PokemonSelectList__form__VIw8Q {
font-size: 0.8em;
text-transform: capitalize; }
.PokemonSelectList__dex__1QHut {
margin-left: auto; }
.PokemonSelectList__form__VIw8Q {
flex: 0 1 100%; }
/*# sourceMappingURL=main.tmp.css.map*/

1116
dist/main-bundle.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -10,35 +10,28 @@ import { League } from 'app/models/League';
import { appReducers } from 'app/index';
import * as ActionsPokemonExplorer from 'app/actions';
import * as ActionsPokemonApp from 'app/actions';
import * as ActionsPokemonExplorer from 'app/components/PokemonExplorer/actions';
import * as ActionsPokemonSelectList from 'app/components/PokemonSelectList/actions';
import { CombatMoveSelectorsOpen, IndividualValueKey, IPokemonAppDispatch, SelectedCombatMoves } from 'app/types';
import { IPokemonAppDispatch, IRouterProps } from 'app/types';
import { Footer } from 'app/components/Footer';
import { Header } from 'app/components/Header';
import { LeagueIvExplorer } from 'app/components/LeagueIvExplorer';
import { MovesExplorer } from 'app/components/MovesExplorer';
import { PokemonDisplay } from 'app/components/PokemonDisplay';
import { ConnectedPokemonExplorer } from 'app/components/PokemonExplorer/PokemonExplorer';
import { PokemonSelectList } from 'app/components/PokemonSelectList/PokemonSelectList';
import { TypeEffectiveDisplay } from 'app/components/TypeEffectiveDisplay';
import { appendQueryString, getCurrentQueryStringVlaues } from 'app/utils/navigation';
import { getCurrentQueryStringVlaues } from 'app/utils/navigation';
import * as styles from 'app/styles/PokemonApp.scss';
type PokemonAppProps = ReturnType<typeof appReducers>;
interface IConnectedPokemonAppProps extends PokemonAppProps, IPokemonAppDispatch {
history : RouteComponentProps['history'];
location : RouteComponentProps['location'];
}
interface IConnectedPokemonAppProps extends PokemonAppProps, IPokemonAppDispatch, IRouterProps {}
// TODO: this should be on PokemonAppState
export type Navigation = 'pokedex';
type SubNavigation = 'pvp' | 'types' | 'moves';
interface IState {
isInterruption : boolean;
activeNavigation : Navigation | null;
widgets : { [ key in SubNavigation ] : boolean };
}
class PokemonApp extends React.Component<IConnectedPokemonAppProps, IState> {
@ -47,13 +40,7 @@ class PokemonApp extends React.Component<IConnectedPokemonAppProps, IState> {
super(props);
this.state = {
isInterruption: false,
activeNavigation: null,
widgets: {
pvp: true,
types: false,
moves: false,
},
};
}
@ -64,7 +51,8 @@ class PokemonApp extends React.Component<IConnectedPokemonAppProps, IState> {
} = this.props;
await Promise.all([
dispatch(ActionsPokemonExplorer.fetchConfig()),
dispatch(ActionsPokemonApp.fetchConfig()),
// TODO: move this action to PokemonApp actions
dispatch(ActionsPokemonSelectList.fetchPokemonList())
]);
dispatch(ActionsPokemonSelectList.setIsLoading(false));
@ -90,6 +78,11 @@ class PokemonApp extends React.Component<IConnectedPokemonAppProps, IState> {
}
public render() {
const {
isInterruption,
attackTypeEffectiveness,
combatMoves,
} = this.props.pokemonAppState;
const {
activePokemonId,
activePokemonForm,
@ -98,36 +91,16 @@ class PokemonApp extends React.Component<IConnectedPokemonAppProps, IState> {
filterTerm,
} = this.props.pokemonSelectListState;
const {
league,
individualValues,
leaguePokemon,
combatMoves,
selectedCombatMoves,
combatMoveSelectorsOpen,
} = this.props.pokemonExplorerState;
const {
isInterruption,
activeNavigation,
widgets,
} = this.state;
const isOverlayShown = isInterruption || activeNavigation === 'pokedex';
const wrapperCss = classNames(
styles.wrapper,
{
[styles.overlaid]: isOverlayShown,
[styles.overlaid]: isInterruption,
}
);
const leftNavCss = classNames(
styles.leftNavigation,
);
const displayWrapperCss = classNames(
styles.displayWrapper,
);
const iconCss = classNames(
'icon',
'pixel',
@ -147,43 +120,6 @@ class PokemonApp extends React.Component<IConnectedPokemonAppProps, IState> {
// }
);
const pvpCss = classNames(
iconCss,
'pvp',
{
active: widgets.pvp,
}
);
const pvpButtonCss = classNames(
// {
// [styles.activeNavigationButton]: widgets.pvp,
// }
);
const badgeCss = classNames(
iconCss,
'badge',
{
active: widgets.types,
}
);
const badgeButtonCss = classNames(
// {
// [styles.activeNavigationButton]: widgets.types,
// }
);
const tmCss = classNames(
iconCss,
'tm',
{
active: widgets.moves,
}
);
const tmButtonCss = classNames(
// {
// [styles.activeNavigationButton]: widgets.moves,
// }
);
return (
<div className={ wrapperCss }>
<Header>
@ -199,114 +135,45 @@ class PokemonApp extends React.Component<IConnectedPokemonAppProps, IState> {
/>
<button className={ pokedexButtonCss } onClick={ this.handlePokedexClick }><i className={ pokedexCss } /></button>
</Header>
<div className={ styles.body }>
<div className={ displayWrapperCss }>
{ leaguePokemon !== null &&
<PokemonDisplay
leaguePokemon={ leaguePokemon }
isHighlighted={ isOverlayShown }
<ConnectedPokemonExplorer
isOverlaid={ isInterruption }
attackTypeEffectiveness={ attackTypeEffectiveness }
combatMoves={ combatMoves }
toggleInterruption={ this.handleToggleInterruption }
history={ this.props.history }
location={ this.props.location }
/>
}
{ widgets.types && leaguePokemon !== null &&
<TypeEffectiveDisplay
effectiveness={ leaguePokemon.effectiveness }
pokemonName={ leaguePokemon.name }
/>
}
{ widgets.pvp && leaguePokemon !== null &&
<LeagueIvExplorer
activeLeague={ league }
leaguePokemon={ leaguePokemon }
individualValues={ individualValues }
handleChangeIndividualValue={ this.handleChangeIndividualValue }
handleMaximizeLevel={ this.handleMaximizeLevel }
handleChangeLeague={ this.handleChangeLeague }
/>
}
{ widgets.moves && leaguePokemon !== null &&
<MovesExplorer
movesById={ combatMoves }
quickMoves={ leaguePokemon.moves.quick }
chargeMoves={ leaguePokemon.moves.cinematic }
selectedMoves={ selectedCombatMoves }
attackTypeEffectiveness={ null }
combatMoveSelectorsOpen={ combatMoveSelectorsOpen }
handleToggleDropdownOpen={ this.handleToggleDropdownOpen }
handleChangeSelectedMove={ this.handleChangeSelectedMove }
/>
}
</div>
<div className={ leftNavCss }>
<button className={ pvpButtonCss } onClick={ this.handlePvpClick }><i className={ pvpCss } /></button>
<button className={ badgeButtonCss } onClick={ this.handleTypesClick }><i className={ badgeCss } /></button>
<button className={ tmButtonCss } onClick={ this.handleMovesClick }><i className={ tmCss } /></button>
</div>
{ isOverlayShown &&
<div className={ styles.overlay } onClick={ this.handleOverlayClick } />
}
</div>
<Footer />
</div>
);
}
private readonly handleToggleDropdownOpen = (menu : keyof CombatMoveSelectorsOpen, isOpen : boolean) => {
private readonly handleSearchInterruption = (isInterruption : boolean) => {
this.setState({
isInterruption: isOpen,
activeNavigation: isInterruption ? 'pokedex' : null,
});
const combatMoveSelectorsOpen : CombatMoveSelectorsOpen = {
...this.props.pokemonExplorerState.combatMoveSelectorsOpen,
[menu]: isOpen, // 3/10/2019: TyepScript is not checking this!
};
this.props.dispatch(ActionsPokemonExplorer.setCombatMoveSelectorsOpen(combatMoveSelectorsOpen));
}
this.props.dispatch(ActionsPokemonApp.setIsInterruption(isInterruption));
private readonly handleOverlayClick = () => {
this.setState({
activeNavigation: null,
isInterruption: false,
});
if (isInterruption) {
this.props.dispatch(ActionsPokemonExplorer.setCombatMoveSelectorsOpen({
quickMove: false,
chargeMove1: false,
chargeMove2: false,
}));
}
}
private readonly handleToggleInterruption = (isInterruption : boolean) => {
this.props.dispatch(ActionsPokemonApp.setIsInterruption(isInterruption));
if (!isInterruption) {
this.setState({
activeNavigation: null,
});
}
}
private readonly handlePokedexClick = () => {
this.setState({
activeNavigation: this.state.activeNavigation !== 'pokedex' ? 'pokedex' : null,
});
}
private readonly handlePvpClick = () => {
const widgets = this.state.widgets;
this.setState({
widgets: {
...widgets,
pvp: !widgets.pvp
}
});
}
private readonly handleTypesClick = () => {
const widgets = this.state.widgets;
this.setState({
widgets: {
...widgets,
types: !widgets.types
}
});
}
private readonly handleMovesClick = () => {
const widgets = this.state.widgets;
this.setState({
widgets: {
...widgets,
moves: !widgets.moves
}
});
this.handleSearchInterruption(true);
}
private readonly handleActivatePokemon = (pokemonId : POGOProtos.Enums.PokemonId, form : POGOProtos.Enums.Form) => {
@ -335,56 +202,10 @@ class PokemonApp extends React.Component<IConnectedPokemonAppProps, IState> {
}
private readonly handleChangeFilter = (filterTerm : string) => {
this.setState({
activeNavigation: 'pokedex',
});
this.handleSearchInterruption(true);
return this.props.dispatch(ActionsPokemonSelectList.filterPokemonList(filterTerm));
}
private readonly handleChangeIndividualValue = (stat : IndividualValueKey, value : number | null) => {
const {
dispatch,
} = this.props;
switch (stat) {
case 'level':
dispatch(ActionsPokemonExplorer.setIvLevel(value));
break;
case 'hp':
dispatch(ActionsPokemonExplorer.setIvHp(value));
break;
case 'atk':
dispatch(ActionsPokemonExplorer.setIvAtk(value));
break;
case 'def':
dispatch(ActionsPokemonExplorer.setIvDef(value));
break;
default:
break;
}
}
private readonly handleMaximizeLevel = () => {
this.props.dispatch(ActionsPokemonExplorer.maximizeLevel());
}
private readonly handleChangeSelectedMove = (moves : SelectedCombatMoves) => {
this.props.dispatch(ActionsPokemonExplorer.setSelectedCombatMoves(moves));
}
private readonly handleChangeLeagueNavigation = (league : League) => {
const {
history,
location,
} = this.props;
history.push({
search: appendQueryString(location, { league: league.toString() })
});
this.handleChangeLeague(league);
}
private readonly handleChangeLeague = (league : League) => {
this.props.dispatch(ActionsPokemonExplorer.setActiveLeague(league));
}
@ -392,6 +213,7 @@ class PokemonApp extends React.Component<IConnectedPokemonAppProps, IState> {
const mapStateToProps = (state : PokemonAppProps) : PokemonAppProps => {
return {
pokemonAppState: state.pokemonAppState,
pokemonExplorerState: state.pokemonExplorerState,
pokemonSelectListState: state.pokemonSelectListState,
};

View File

@ -1,71 +1,23 @@
import { action } from 'typesafe-actions';
import { CombatMoveSelectorsOpen, PokemonExplorerActionTypes, SelectedCombatMoves, ThunkResult } from 'app/types';
import { PokemonAppActionTypes, ThunkResult } from 'app/types';
import { calculateMaxLevelForLeague } from 'app/utils/calculator';
import { ILeaguePokemon, League } from 'app/models/League';
import { AttackTypeEffectiveness } from 'app/models/Config';
import { CombatMoveStats, IMaxStats } from 'app/models/Pokemon';
export const setIsLoading = (isLoading : boolean) => action(PokemonExplorerActionTypes.SET_IS_LOADING, { isLoading });
export const setIsInterruption = (isInterruption : boolean) => action(PokemonAppActionTypes.SET_IS_INTERRUPTION, { isInterruption });
export const setMaxPossibleStats = (maxStats : IMaxStats) => action(PokemonAppActionTypes.SET_MAX_STATS, { maxStats });
export const setMaxPossibleStats = (maxStats : IMaxStats) => action(PokemonExplorerActionTypes.SET_MAX_STATS, { maxStats });
export const setAttackTypeEffectiveness = (attackTypeEffectiveness : AttackTypeEffectiveness) => action(PokemonAppActionTypes.SET_COMBAT_MOVE_STATS, { attackTypeEffectiveness });
export const setCombatMoveStats = (combatMoves : CombatMoveStats) => action(PokemonExplorerActionTypes.SET_COMBAT_MOVE_STATS, { combatMoves });
export const setLeaguePokemon = (leaguePokemon : ILeaguePokemon | null) => action(PokemonExplorerActionTypes.SET_LEAGUE_POKEMON, { leaguePokemon });
export const setIvLevel = (level : number | null) => action(PokemonExplorerActionTypes.SET_IV_LEVEL, { level });
export const setIvHp = (ivHp : number | null) => action(PokemonExplorerActionTypes.SET_IV_HP, { ivHp });
export const setIvAtk = (ivAtk : number | null) => action(PokemonExplorerActionTypes.SET_IV_ATK, { ivAtk });
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 setSelectedCombatMoves = (moves : SelectedCombatMoves) => action(PokemonExplorerActionTypes.SET_SELECTED_COMBAT_MOVES, { moves });
export const setCombatMoveSelectorsOpen = (selectorsOpen : CombatMoveSelectorsOpen) => action(PokemonExplorerActionTypes.SET_COMBAT_MOVE_SELECTORS_OPEN, { selectorsOpen });
export const setCombatMoveStats = (combatMoves : CombatMoveStats) => action(PokemonAppActionTypes.SET_COMBAT_MOVE_STATS, { combatMoves });
export const fetchConfig = (
) : ThunkResult<Promise<void>> => {
return async (dispatch, getState, extraArguments) => {
const config = await extraArguments.services.pokemonService.getConfig();
dispatch(setMaxPossibleStats(config.maxPossibleStats));
dispatch(setAttackTypeEffectiveness(config.attackTypeEffectiveness));
dispatch(setCombatMoveStats(config.combatMoves));
};
};
export const maximizeLevel = (
) : ThunkResult<Promise<void>> => {
return async (dispatch, getState, extraArguments) => {
const pokemonExplorerState = getState().pokemonExplorerState;
const {
ivHp,
ivAtk,
ivDef,
} = pokemonExplorerState.individualValues;
if (pokemonExplorerState.leaguePokemon !== null) {
const pokemonLeagueValues = pokemonExplorerState.leaguePokemon.pvp[pokemonExplorerState.league];
const statsSet = pokemonLeagueValues.some((stats) => {
if (((ivHp === null) || (stats.ivHp === ivHp)) &&
((ivAtk === null) || (stats.ivAtk === ivAtk)) &&
((ivDef === null) || (stats.ivDef === ivDef))
) {
dispatch(setIvHp(stats.ivHp));
dispatch(setIvAtk(stats.ivAtk));
dispatch(setIvDef(stats.ivDef));
dispatch(setIvLevel(stats.level));
return true;
}
return false;
});
if (!statsSet && ivHp !== null && ivAtk !== null && ivDef !== null) {
dispatch(setIvLevel(calculateMaxLevelForLeague(pokemonExplorerState.leaguePokemon.stats, ivHp, ivAtk, ivDef, pokemonExplorerState.league)));
}
}
};
};

View File

@ -2,7 +2,7 @@ import React from 'react';
import classNames from 'classnames';
import { IIndividualValues, IndividualValueKey } from '../types';
import { IIndividualValues, IndividualValueKey } from 'app/components/PokemonExplorer/types';
import * as styles from 'app/styles/IvForm.scss';

View File

@ -6,7 +6,7 @@ import { IBestWorstStats, ILeaguePokemon, League, MaxCpByLeague } from 'app/mode
import { Grade, IStats } from 'app/models/Pokemon';
import { calculateCp, calculateStatAtLevel } from 'app/utils/calculator';
import { IIndividualValues, IndividualValueKey } from 'app/types';
import { IIndividualValues, IndividualValueKey } from 'app/components/PokemonExplorer/types';
import { IvForm } from './IvForm';
import { LeagueSelector } from './LeagueSelector';

View File

@ -6,8 +6,8 @@ import { FixedSizeList } from 'react-window';
import classNames from 'classnames';
import { IIndividualValues } from 'app/components/PokemonExplorer/types';
import { Grade, IStats } from 'app/models/Pokemon';
import { IIndividualValues } from 'app/types';
import * as styles from 'app/styles/LeagueStatsList.scss';

View File

@ -5,7 +5,7 @@ import classNames from 'classnames';
import { AttackTypeEffectiveness } from 'app/models/Config';
import { CombatMoveStats, ICombatMoveStats, IPokemonMove } from 'app/models/Pokemon';
import { CombatMoveSelectorsOpen, SelectedCombatMoves } from 'app/types';
import { CombatMoveSelectorsOpen, SelectedCombatMoves } from 'app/components/PokemonExplorer/types';
import { MovesDropdown } from 'app/components/MovesDropdown';
import { TypeIndicator } from './TypeIndicator';
@ -21,7 +21,7 @@ export interface IMovesExplorerProps {
chargeMove1 : IPokemonMove | null;
chargeMove2 : IPokemonMove | null;
};
attackTypeEffectiveness : AttackTypeEffectiveness | null;
attackTypeEffectiveness : AttackTypeEffectiveness;
combatMoveSelectorsOpen : CombatMoveSelectorsOpen;
handleToggleDropdownOpen : (menu : keyof CombatMoveSelectorsOpen, isOpen : boolean) => void;
handleChangeSelectedMove : (moves : SelectedCombatMoves) => void;

View File

@ -0,0 +1,298 @@
import React from 'react';
import { connect } from 'react-redux';
import { RouteComponentProps } from 'react-router-dom';
import classNames from 'classnames';
import { AttackTypeEffectiveness } from 'app/models/Config';
import { League } from 'app/models/League';
import { CombatMoveStats } from 'app/models/Pokemon';
import * as ActionsPokemonExplorer from 'app/components/PokemonExplorer/actions';
import {
CombatMoveSelectorsOpen,
IndividualValueKey,
IPokemonExplorerDispatch,
IPokemonExplorerStore,
SelectedCombatMoves
} from 'app/components/PokemonExplorer/types';
import { IRouterProps } from 'app/types';
import { LeagueIvExplorer } from 'app/components/LeagueIvExplorer';
import { MovesExplorer } from 'app/components/MovesExplorer';
import { PokemonDisplay } from 'app/components/PokemonDisplay';
import { TypeEffectiveDisplay } from 'app/components/TypeEffectiveDisplay';
import { appendQueryString } from 'app/utils/navigation';
import * as styles from 'app/styles/PokemonApp.scss';
// TODO: better way to expose IRouterProps than just passing them in???
interface IPokemonExplorerProps extends IRouterProps {
isOverlaid : boolean;
attackTypeEffectiveness : AttackTypeEffectiveness;
combatMoves : CombatMoveStats;
toggleInterruption : (isInterruption : boolean) => void;
}
interface IConnectedPokemonExplorerProps extends IPokemonExplorerStore, IPokemonExplorerDispatch, IPokemonExplorerProps {}
type SubNavigation = 'pvp' | 'types' | 'moves';
interface IState {
widgets : { [ key in SubNavigation ] : boolean };
}
class PokemonExplorer extends React.Component<IConnectedPokemonExplorerProps, IState> {
constructor(props : IConnectedPokemonExplorerProps) {
super(props);
this.state = {
widgets: {
pvp: true,
types: false,
moves: false,
},
};
}
public render() {
const {
combatMoves,
attackTypeEffectiveness,
} = this.props;
const {
league,
individualValues,
leaguePokemon,
selectedCombatMoves,
combatMoveSelectorsOpen,
} = this.props.pokemonExplorerState;
const {
widgets,
} = this.state;
const isOverlayShown = this.props.isOverlaid || combatMoveSelectorsOpen.quickMove || combatMoveSelectorsOpen.chargeMove1 || combatMoveSelectorsOpen.chargeMove2;
const leftNavCss = classNames(
styles.leftNavigation,
);
const displayWrapperCss = classNames(
styles.displayWrapper,
);
const iconCss = classNames(
'icon',
'pixel',
'sprite',
);
const pvpCss = classNames(
iconCss,
'pvp',
{
active: widgets.pvp,
}
);
const pvpButtonCss = classNames(
// {
// [styles.activeNavigationButton]: widgets.pvp,
// }
);
const badgeCss = classNames(
iconCss,
'badge',
{
active: widgets.types,
}
);
const badgeButtonCss = classNames(
// {
// [styles.activeNavigationButton]: widgets.types,
// }
);
const tmCss = classNames(
iconCss,
'tm',
{
active: widgets.moves,
}
);
const tmButtonCss = classNames(
// {
// [styles.activeNavigationButton]: widgets.moves,
// }
);
return (
<div className={ styles.body }>
<div className={ displayWrapperCss }>
{ leaguePokemon !== null &&
<PokemonDisplay
leaguePokemon={ leaguePokemon }
isHighlighted={ isOverlayShown }
/>
}
{ widgets.types && leaguePokemon !== null &&
<TypeEffectiveDisplay
effectiveness={ leaguePokemon.effectiveness }
pokemonName={ leaguePokemon.name }
/>
}
{ widgets.pvp && leaguePokemon !== null &&
<LeagueIvExplorer
activeLeague={ league }
leaguePokemon={ leaguePokemon }
individualValues={ individualValues }
handleChangeIndividualValue={ this.handleChangeIndividualValue }
handleMaximizeLevel={ this.handleMaximizeLevel }
handleChangeLeague={ this.handleChangeLeague }
/>
}
{ widgets.moves && leaguePokemon !== null &&
<MovesExplorer
movesById={ combatMoves }
quickMoves={ leaguePokemon.moves.quick }
chargeMoves={ leaguePokemon.moves.cinematic }
selectedMoves={ selectedCombatMoves }
attackTypeEffectiveness={ attackTypeEffectiveness }
combatMoveSelectorsOpen={ combatMoveSelectorsOpen }
handleToggleDropdownOpen={ this.handleToggleDropdownOpen }
handleChangeSelectedMove={ this.handleChangeSelectedMove }
/>
}
</div>
<div className={ leftNavCss }>
<button className={ pvpButtonCss } onClick={ this.handlePvpClick }><i className={ pvpCss } /></button>
<button className={ badgeButtonCss } onClick={ this.handleTypesClick }><i className={ badgeCss } /></button>
<button className={ tmButtonCss } onClick={ this.handleMovesClick }><i className={ tmCss } /></button>
</div>
{ isOverlayShown &&
<div className={ styles.overlay } onClick={ this.handleOverlayClick } />
}
</div>
);
}
private readonly handleToggleDropdownOpen = (menu : keyof CombatMoveSelectorsOpen, isOpen : boolean) => {
const combatMoveSelectorsOpen : CombatMoveSelectorsOpen = {
...this.props.pokemonExplorerState.combatMoveSelectorsOpen,
[menu]: isOpen, // 3/10/2019: TyepScript is not checking this!
};
this.props.dispatch(ActionsPokemonExplorer.setCombatMoveSelectorsOpen(combatMoveSelectorsOpen));
this.props.toggleInterruption(true);
}
private readonly handleOverlayClick = () => {
this.props.dispatch(ActionsPokemonExplorer.setCombatMoveSelectorsOpen({
quickMove: false,
chargeMove1: false,
chargeMove2: false,
}));
this.props.toggleInterruption(false);
}
private readonly handlePvpClick = () => {
const widgets = this.state.widgets;
this.setState({
widgets: {
...widgets,
pvp: !widgets.pvp
}
});
}
private readonly handleTypesClick = () => {
const widgets = this.state.widgets;
this.setState({
widgets: {
...widgets,
types: !widgets.types
}
});
}
private readonly handleMovesClick = () => {
const widgets = this.state.widgets;
this.setState({
widgets: {
...widgets,
moves: !widgets.moves
}
});
}
private readonly handleChangeIndividualValue = (stat : IndividualValueKey, value : number | null) => {
const {
dispatch,
} = this.props;
switch (stat) {
case 'level':
dispatch(ActionsPokemonExplorer.setIvLevel(value));
break;
case 'hp':
dispatch(ActionsPokemonExplorer.setIvHp(value));
break;
case 'atk':
dispatch(ActionsPokemonExplorer.setIvAtk(value));
break;
case 'def':
dispatch(ActionsPokemonExplorer.setIvDef(value));
break;
default:
break;
}
}
private readonly handleMaximizeLevel = () => {
this.props.dispatch(ActionsPokemonExplorer.maximizeLevel());
}
private readonly handleChangeSelectedMove = (moves : SelectedCombatMoves) => {
this.props.dispatch(ActionsPokemonExplorer.setSelectedCombatMoves(moves));
}
// TODO: make this not overwrite other query parameters
private readonly handleChangeLeagueNavigation = (league : League) => {
const {
history,
location,
} = this.props;
history.push({
search: appendQueryString(location, { league: league.toString() })
});
this.handleChangeLeague(league);
}
private readonly handleChangeLeague = (league : League) => {
this.props.dispatch(ActionsPokemonExplorer.setActiveLeague(league));
}
}
const mapStateToProps = (state : IPokemonExplorerStore) : IPokemonExplorerStore => {
return {
...state,
};
};
const mapDispatchToProps = (dispatch : IPokemonExplorerDispatch['dispatch']) : IPokemonExplorerDispatch => {
return {
dispatch
};
};
const mergeProps = (state : IPokemonExplorerStore, dispatchProps : IPokemonExplorerDispatch, ownProps : IPokemonExplorerProps) : IConnectedPokemonExplorerProps => {
return {
...state,
...dispatchProps,
...ownProps,
history: ownProps.history,
location: ownProps.location,
};
};
export const ConnectedPokemonExplorer = connect(mapStateToProps, mapDispatchToProps, mergeProps)(PokemonExplorer);

View File

@ -0,0 +1,62 @@
import { action } from 'typesafe-actions';
import {
CombatMoveSelectorsOpen,
PokemonExplorerActionTypes,
SelectedCombatMoves,
ThunkResult
} from 'app/components/PokemonExplorer/types';
import { calculateMaxLevelForLeague } from 'app/utils/calculator';
import { ILeaguePokemon, League } from 'app/models/League';
export const setIsLoading = (isLoading : boolean) => action(PokemonExplorerActionTypes.SET_IS_LOADING, { isLoading });
export const setLeaguePokemon = (leaguePokemon : ILeaguePokemon | null) => action(PokemonExplorerActionTypes.SET_LEAGUE_POKEMON, { leaguePokemon });
export const setIvLevel = (level : number | null) => action(PokemonExplorerActionTypes.SET_IV_LEVEL, { level });
export const setIvHp = (ivHp : number | null) => action(PokemonExplorerActionTypes.SET_IV_HP, { ivHp });
export const setIvAtk = (ivAtk : number | null) => action(PokemonExplorerActionTypes.SET_IV_ATK, { ivAtk });
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 setSelectedCombatMoves = (moves : SelectedCombatMoves) => action(PokemonExplorerActionTypes.SET_SELECTED_COMBAT_MOVES, { moves });
export const setCombatMoveSelectorsOpen = (selectorsOpen : CombatMoveSelectorsOpen) => action(PokemonExplorerActionTypes.SET_COMBAT_MOVE_SELECTORS_OPEN, { selectorsOpen });
export const maximizeLevel = (
) : ThunkResult<Promise<void>> => {
return async (dispatch, getState, extraArguments) => {
const pokemonExplorerState = getState().pokemonExplorerState;
const {
ivHp,
ivAtk,
ivDef,
} = pokemonExplorerState.individualValues;
if (pokemonExplorerState.leaguePokemon !== null) {
const pokemonLeagueValues = pokemonExplorerState.leaguePokemon.pvp[pokemonExplorerState.league];
const statsSet = pokemonLeagueValues.some((stats) => {
if (((ivHp === null) || (stats.ivHp === ivHp)) &&
((ivAtk === null) || (stats.ivAtk === ivAtk)) &&
((ivDef === null) || (stats.ivDef === ivDef))
) {
dispatch(setIvHp(stats.ivHp));
dispatch(setIvAtk(stats.ivAtk));
dispatch(setIvDef(stats.ivDef));
dispatch(setIvLevel(stats.level));
return true;
}
return false;
});
if (!statsSet && ivHp !== null && ivAtk !== null && ivDef !== null) {
dispatch(setIvLevel(calculateMaxLevelForLeague(pokemonExplorerState.leaguePokemon.stats, ivHp, ivAtk, ivDef, pokemonExplorerState.league)));
}
}
};
};

View File

@ -0,0 +1,144 @@
import { Reducer } from 'redux';
import { League } from 'app/models/League';
import * as Actions from 'app/components/PokemonExplorer/actions';
import { IPokemonExplorerState, PokemonExplorerActionTypes } from 'app/components/PokemonExplorer/types';
export const initialState : IPokemonExplorerState = {
isLoading: false,
leaguePokemon: null,
individualValues: {
level: null,
ivHp: null,
ivAtk: null,
ivDef: null,
},
league: League.GREAT,
selectedCombatMoves: {
quickMove: null,
chargeMove1: null,
chargeMove2: null,
},
combatMoveSelectorsOpen: {
quickMove: false,
chargeMove1: false,
chargeMove2: false,
},
};
const reduceSetIsLoading = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setIsLoading>
) : IPokemonExplorerState => ({
...state,
isLoading: action.payload.isLoading,
});
const reduceSetLeaguePokemon = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setLeaguePokemon>
) : IPokemonExplorerState => ({
...state,
leaguePokemon: action.payload.leaguePokemon,
});
const reduceSetIvLevel = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setIvLevel>
) : IPokemonExplorerState => ({
...state,
individualValues: {
...state.individualValues,
level: action.payload.level,
}
});
const reduceSetIvHp = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setIvHp>
) : IPokemonExplorerState => ({
...state,
individualValues: {
...state.individualValues,
ivHp: action.payload.ivHp,
}
});
const reduceSetIvAtk = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setIvAtk>
) : IPokemonExplorerState => ({
...state,
individualValues: {
...state.individualValues,
ivAtk: action.payload.ivAtk,
}
});
const reduceSetIvDef = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setIvDef>
) : IPokemonExplorerState => ({
...state,
individualValues: {
...state.individualValues,
ivDef: action.payload.ivDef,
}
});
const reduceSetActiveLeague = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setActiveLeague>
) : IPokemonExplorerState => ({
...state,
league: action.payload.league
});
const reduceSetSelectedCombatMoves = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setSelectedCombatMoves>
) : IPokemonExplorerState => ({
...state,
selectedCombatMoves: {
...action.payload.moves
}
});
const reduceSetCombatMoveSelectorsOpen = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setCombatMoveSelectorsOpen>
) : IPokemonExplorerState => ({
...state,
combatMoveSelectorsOpen: {
...action.payload.selectorsOpen
}
});
export const PokemonExplorerReducers : Reducer<IPokemonExplorerState> = (
state : IPokemonExplorerState = initialState,
action,
) : IPokemonExplorerState => {
switch (action.type) {
case PokemonExplorerActionTypes.SET_IS_LOADING:
return reduceSetIsLoading(state, action as ReturnType<typeof Actions.setIsLoading>);
case PokemonExplorerActionTypes.SET_LEAGUE_POKEMON:
return reduceSetLeaguePokemon(state, action as ReturnType<typeof Actions.setLeaguePokemon>);
case PokemonExplorerActionTypes.SET_IV_LEVEL:
return reduceSetIvLevel(state, action as ReturnType<typeof Actions.setIvLevel>);
case PokemonExplorerActionTypes.SET_IV_HP:
return reduceSetIvHp(state, action as ReturnType<typeof Actions.setIvHp>);
case PokemonExplorerActionTypes.SET_IV_ATK:
return reduceSetIvAtk(state, action as ReturnType<typeof Actions.setIvAtk>);
case PokemonExplorerActionTypes.SET_IV_DEF:
return reduceSetIvDef(state, action as ReturnType<typeof Actions.setIvDef>);
case PokemonExplorerActionTypes.SET_ACTIVE_LEAGUE:
return reduceSetActiveLeague(state, action as ReturnType<typeof Actions.setActiveLeague>);
case PokemonExplorerActionTypes.SET_SELECTED_COMBAT_MOVES:
return reduceSetSelectedCombatMoves(state, action as ReturnType<typeof Actions.setSelectedCombatMoves>);
case PokemonExplorerActionTypes.SET_COMBAT_MOVE_SELECTORS_OPEN:
return reduceSetCombatMoveSelectorsOpen(state, action as ReturnType<typeof Actions.setCombatMoveSelectorsOpen>);
default:
return state;
}
};

View File

@ -0,0 +1,66 @@
import { Action } from 'redux';
import { ThunkAction, ThunkDispatch } from 'redux-thunk';
import { IProviderExtraArguments } from 'common/models/IProviderExtraArguments';
import { ILeaguePokemon, League } from 'app/models/League';
import { IPokemonMove } from 'app/models/Pokemon';
import { PokemonService } from 'api/PokemonService';
export type IndividualValueKey = 'level' | 'hp' | 'atk' | 'def';
export interface IIndividualValues {
level : number | null;
ivHp : number | null;
ivAtk : number | null;
ivDef : number | null;
}
type MoveTypes = 'quickMove' | 'chargeMove1' | 'chargeMove2';
export type SelectedCombatMoves = {
[ key in MoveTypes ] : IPokemonMove | null;
};
export type CombatMoveSelectorsOpen = {
[ key in MoveTypes ] : boolean;
};
export interface IPokemonExplorerState {
isLoading : boolean;
leaguePokemon : ILeaguePokemon | null;
individualValues : IIndividualValues;
league : League;
selectedCombatMoves : SelectedCombatMoves;
combatMoveSelectorsOpen : CombatMoveSelectorsOpen;
}
export const PokemonExplorerActionTypes = {
SET_IS_LOADING: 'POKEMON_EXPLORER/SET_IS_LOADING',
SET_LEAGUE_POKEMON: 'POKEMON_EXPLORER/SET_LEAGUE_POKEMON',
SET_IV_LEVEL: 'POKEMON_EXPLORER/SET_IV_LEVEL',
SET_IV_HP: 'POKEMON_EXPLORER/SET_IV_HP',
SET_IV_ATK: 'POKEMON_EXPLORER/SET_IV_ATK',
SET_IV_DEF: 'POKEMON_EXPLORER/SET_IV_DEF',
SET_ACTIVE_LEAGUE: 'POKEMON_EXPLORER/SET_ACTIVE_LEAGUE',
SET_SELECTED_COMBAT_MOVES: 'POKEMON_EXPLORER/SET_SELECTED_COMBAT_MOVES',
SET_COMBAT_MOVE_SELECTORS_OPEN: 'POKEMON_EXPLORER/SET_COMBAT_MOVE_SELECTORS_OPEN',
};
export interface IPokemonExplorerStore {
pokemonExplorerState : IPokemonExplorerState;
}
export interface IPokemonExplorerServices {
pokemonService : PokemonService;
}
export interface IPokemonExplorerExtraArguments extends IProviderExtraArguments {
services : IPokemonExplorerServices;
}
export type ThunkResult<R> = ThunkAction<R, IPokemonExplorerStore, IPokemonExplorerExtraArguments, Action>;
type ThunkDispatchPokemonExplorer = ThunkDispatch<IPokemonExplorerStore, IPokemonExplorerExtraArguments, Action>;
export interface IPokemonExplorerDispatch {
dispatch : ThunkDispatchPokemonExplorer;
}

View File

@ -9,12 +9,14 @@ import { IPokemonAppExtraArguments } from 'app/types';
import { PokemonService } from 'api/PokemonService';
import { PokemonExplorerReducers } from 'app/components/PokemonExplorer/reducers';
import { PokemonSelectListReducers } from 'app/components/PokemonSelectList/reducers';
import { PokemonExplorerReducers } from 'app/reducers';
import { PokemonAppReducers } from 'app/reducers';
import { ConnectedPokemonApp } from './PokemonApp';
export const appReducers = Redux.combineReducers({
pokemonAppState: PokemonAppReducers,
pokemonSelectListState: PokemonSelectListReducers,
pokemonExplorerState: PokemonExplorerReducers,
});

View File

@ -1,172 +1,67 @@
import { Reducer } from 'redux';
import { League } from 'app/models/League';
import * as Actions from 'app/actions';
import { IPokemonExplorerState, PokemonExplorerActionTypes } from 'app/types';
import { IPokemonAppState, PokemonAppActionTypes } from 'app/types';
export const initialState : IPokemonExplorerState = {
isLoading: false,
leaguePokemon: null,
export const initialState : IPokemonAppState = {
isInterruption: false,
maxPossibleStats: {
baseStamina: 0,
baseAttack: 0,
baseDefense: 0,
level: 0,
},
individualValues: {
level: null,
ivHp: null,
ivAtk: null,
ivDef: null,
},
league: League.GREAT,
attackTypeEffectiveness: new Map(),
combatMoves: new Map(),
selectedCombatMoves: {
quickMove: null,
chargeMove1: null,
chargeMove2: null,
},
combatMoveSelectorsOpen: {
quickMove: false,
chargeMove1: false,
chargeMove2: false,
},
};
const reduceSetIsLoading = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setIsLoading>
) : IPokemonExplorerState => ({
const reduceSetInterruption = (
state : IPokemonAppState,
action : ReturnType<typeof Actions.setIsInterruption>
) : IPokemonAppState => ({
...state,
isLoading: action.payload.isLoading,
isInterruption: action.payload.isInterruption,
});
const reduceSetMaxPossibleStats = (
state : IPokemonExplorerState,
state : IPokemonAppState,
action : ReturnType<typeof Actions.setMaxPossibleStats>
) : IPokemonExplorerState => ({
) : IPokemonAppState => ({
...state,
maxPossibleStats: {
...action.payload.maxStats,
},
});
const reduceSetAttackTypeEffectiveness = (
state : IPokemonAppState,
action : ReturnType<typeof Actions.setAttackTypeEffectiveness>
) : IPokemonAppState => ({
...state,
attackTypeEffectiveness: action.payload.attackTypeEffectiveness,
});
const reduceSetCombatMoveStats = (
state : IPokemonExplorerState,
state : IPokemonAppState,
action : ReturnType<typeof Actions.setCombatMoveStats>
) : IPokemonExplorerState => ({
) : IPokemonAppState => ({
...state,
combatMoves: action.payload.combatMoves,
});
const reduceSetLeaguePokemon = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setLeaguePokemon>
) : IPokemonExplorerState => ({
...state,
leaguePokemon: action.payload.leaguePokemon,
});
const reduceSetIvLevel = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setIvLevel>
) : IPokemonExplorerState => ({
...state,
individualValues: {
...state.individualValues,
level: action.payload.level,
}
});
const reduceSetIvHp = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setIvHp>
) : IPokemonExplorerState => ({
...state,
individualValues: {
...state.individualValues,
ivHp: action.payload.ivHp,
}
});
const reduceSetIvAtk = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setIvAtk>
) : IPokemonExplorerState => ({
...state,
individualValues: {
...state.individualValues,
ivAtk: action.payload.ivAtk,
}
});
const reduceSetIvDef = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setIvDef>
) : IPokemonExplorerState => ({
...state,
individualValues: {
...state.individualValues,
ivDef: action.payload.ivDef,
}
});
const reduceSetActiveLeague = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setActiveLeague>
) : IPokemonExplorerState => ({
...state,
league: action.payload.league
});
const reduceSetSelectedCombatMoves = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setSelectedCombatMoves>
) : IPokemonExplorerState => ({
...state,
selectedCombatMoves: {
...action.payload.moves
}
});
const reduceSetCombatMoveSelectorsOpen = (
state : IPokemonExplorerState,
action : ReturnType<typeof Actions.setCombatMoveSelectorsOpen>
) : IPokemonExplorerState => ({
...state,
combatMoveSelectorsOpen: {
...action.payload.selectorsOpen
}
});
export const PokemonExplorerReducers : Reducer<IPokemonExplorerState> = (
state : IPokemonExplorerState = initialState,
export const PokemonAppReducers : Reducer<IPokemonAppState> = (
state : IPokemonAppState = initialState,
action,
) : IPokemonExplorerState => {
) : IPokemonAppState => {
switch (action.type) {
case PokemonExplorerActionTypes.SET_IS_LOADING:
return reduceSetIsLoading(state, action as ReturnType<typeof Actions.setIsLoading>);
case PokemonExplorerActionTypes.SET_MAX_STATS:
case PokemonAppActionTypes.SET_IS_INTERRUPTION:
return reduceSetInterruption(state, action as ReturnType<typeof Actions.setIsInterruption>);
case PokemonAppActionTypes.SET_MAX_STATS:
return reduceSetMaxPossibleStats(state, action as ReturnType<typeof Actions.setMaxPossibleStats>);
case PokemonExplorerActionTypes.SET_COMBAT_MOVE_STATS:
case PokemonAppActionTypes.SET_ATTACK_TYPE_EFFECTIVENESS:
return reduceSetAttackTypeEffectiveness(state, action as ReturnType<typeof Actions.setAttackTypeEffectiveness>);
case PokemonAppActionTypes.SET_COMBAT_MOVE_STATS:
return reduceSetCombatMoveStats(state, action as ReturnType<typeof Actions.setCombatMoveStats>);
case PokemonExplorerActionTypes.SET_LEAGUE_POKEMON:
return reduceSetLeaguePokemon(state, action as ReturnType<typeof Actions.setLeaguePokemon>);
case PokemonExplorerActionTypes.SET_IV_LEVEL:
return reduceSetIvLevel(state, action as ReturnType<typeof Actions.setIvLevel>);
case PokemonExplorerActionTypes.SET_IV_HP:
return reduceSetIvHp(state, action as ReturnType<typeof Actions.setIvHp>);
case PokemonExplorerActionTypes.SET_IV_ATK:
return reduceSetIvAtk(state, action as ReturnType<typeof Actions.setIvAtk>);
case PokemonExplorerActionTypes.SET_IV_DEF:
return reduceSetIvDef(state, action as ReturnType<typeof Actions.setIvDef>);
case PokemonExplorerActionTypes.SET_ACTIVE_LEAGUE:
return reduceSetActiveLeague(state, action as ReturnType<typeof Actions.setActiveLeague>);
case PokemonExplorerActionTypes.SET_SELECTED_COMBAT_MOVES:
return reduceSetSelectedCombatMoves(state, action as ReturnType<typeof Actions.setSelectedCombatMoves>);
case PokemonExplorerActionTypes.SET_COMBAT_MOVE_SELECTORS_OPEN:
return reduceSetCombatMoveSelectorsOpen(state, action as ReturnType<typeof Actions.setCombatMoveSelectorsOpen>);
default:
return state;
}

View File

@ -1,22 +1,35 @@
import POGOProtos from 'pogo-protos';
import { RouteComponentProps } from 'react-router-dom';
import { Action } from 'redux';
import { ThunkAction, ThunkDispatch } from 'redux-thunk';
import { IProviderExtraArguments } from 'common/models/IProviderExtraArguments';
import { IPokemonExplorerStore } from 'app/components/PokemonExplorer/types';
import { IPokemonSelectListState } from 'app/components/PokemonSelectList/types';
import { ILeaguePokemon, League } from 'app/models/League';
import { CombatMoveStats, IMaxStats, IPokemonMove } from 'app/models/Pokemon';
import { AttackTypeEffectiveness } from 'app/models/Config';
import { CombatMoveStats, IMaxStats } from 'app/models/Pokemon';
import { PokemonService } from 'api/PokemonService';
export interface IPokemonAppStore {
pokemonSelectListState : IPokemonSelectListState;
pokemonExplorerState : IPokemonExplorerState;
export interface IPokemonAppState {
isInterruption : boolean;
maxPossibleStats : IMaxStats;
attackTypeEffectiveness : AttackTypeEffectiveness;
combatMoves : CombatMoveStats;
}
export const PokemonAppActionTypes = {
SET_IS_INTERRUPTION: 'POKEMON_APP/SET_IS_INTERRUPTION',
SET_MAX_STATS: 'POKEMON_APP/SET_MAX_STATS',
SET_ATTACK_TYPE_EFFECTIVENESS: 'POKEMON_APP/SET_ATTACK_TYPE_EFFECTIVENESS',
SET_COMBAT_MOVE_STATS: 'POKEMON_APP/SET_COMBAT_MOVE_STATS',
};
export interface IPokemonAppStore extends IPokemonExplorerStore {
pokemonSelectListState : IPokemonSelectListState;
}
// TODO: do i need to import/extend a service from PokemonExplorer?
export interface IPokemonAppServices {
pokemonService : PokemonService;
}
@ -25,51 +38,13 @@ export interface IPokemonAppExtraArguments extends IProviderExtraArguments {
services : IPokemonAppServices;
}
export interface IRouterProps {
history : RouteComponentProps['history'];
location : RouteComponentProps['location'];
}
export type ThunkResult<R> = ThunkAction<R, IPokemonAppStore, IPokemonAppExtraArguments, Action>;
type ThunkDispatchPokemonApp = ThunkDispatch<IPokemonAppStore, IPokemonAppExtraArguments, Action>;
export interface IPokemonAppDispatch {
dispatch : ThunkDispatchPokemonApp;
}
export type IndividualValueKey = 'level' | 'hp' | 'atk' | 'def';
export interface IIndividualValues {
level : number | null;
ivHp : number | null;
ivAtk : number | null;
ivDef : number | null;
}
type MoveTypes = 'quickMove' | 'chargeMove1' | 'chargeMove2';
export type SelectedCombatMoves = {
[ key in MoveTypes ] : IPokemonMove | null;
};
export type CombatMoveSelectorsOpen = {
[ key in MoveTypes ] : boolean;
};
export interface IPokemonExplorerState {
isLoading : boolean;
leaguePokemon : ILeaguePokemon | null;
maxPossibleStats : IMaxStats;
individualValues : IIndividualValues;
league : League;
combatMoves : CombatMoveStats;
selectedCombatMoves : SelectedCombatMoves;
combatMoveSelectorsOpen : CombatMoveSelectorsOpen;
}
export const PokemonExplorerActionTypes = {
SET_IS_LOADING: 'POKEMON_EXPLORER/SET_IS_LOADING',
SET_MAX_STATS: 'POKEMON_EXPLORER/SET_MAX_STATS',
SET_COMBAT_MOVE_STATS: 'POKEMON_EXPLORER/SET_COMBAT_MOVE_STATS',
SET_LEAGUE_POKEMON: 'POKEMON_EXPLORER/SET_LEAGUE_POKEMON',
SET_IV_LEVEL: 'POKEMON_EXPLORER/SET_IV_LEVEL',
SET_IV_HP: 'POKEMON_EXPLORER/SET_IV_HP',
SET_IV_ATK: 'POKEMON_EXPLORER/SET_IV_ATK',
SET_IV_DEF: 'POKEMON_EXPLORER/SET_IV_DEF',
SET_ACTIVE_LEAGUE: 'POKEMON_EXPLORER/SET_ACTIVE_LEAGUE',
SET_SELECTED_COMBAT_MOVES: 'POKEMON_EXPLORER/SET_SELECTED_COMBAT_MOVES',
SET_COMBAT_MOVE_SELECTORS_OPEN: 'POKEMON_EXPLORER/SET_COMBAT_MOVE_SELECTORS_OPEN',
};