split pokemon explorer from pokemon app
This commit is contained in:
parent
7cd14f2b58
commit
dd37703417
126
dist/app.css
vendored
126
dist/app.css
vendored
@ -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*/
|
||||
1120
dist/main-bundle.js
vendored
1120
dist/main-bundle.js
vendored
File diff suppressed because it is too large
Load Diff
@ -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 }
|
||||
/>
|
||||
}
|
||||
{ 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>
|
||||
<ConnectedPokemonExplorer
|
||||
isOverlaid={ isInterruption }
|
||||
attackTypeEffectiveness={ attackTypeEffectiveness }
|
||||
combatMoves={ combatMoves }
|
||||
toggleInterruption={ this.handleToggleInterruption }
|
||||
history={ this.props.history }
|
||||
location={ this.props.location }
|
||||
/>
|
||||
<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));
|
||||
|
||||
if (isInterruption) {
|
||||
this.props.dispatch(ActionsPokemonExplorer.setCombatMoveSelectorsOpen({
|
||||
quickMove: false,
|
||||
chargeMove1: false,
|
||||
chargeMove2: false,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private readonly handleOverlayClick = () => {
|
||||
this.setState({
|
||||
activeNavigation: null,
|
||||
isInterruption: false,
|
||||
});
|
||||
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,
|
||||
};
|
||||
|
||||
@ -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)));
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
298
src/ts/app/components/PokemonExplorer/PokemonExplorer.tsx
Normal file
298
src/ts/app/components/PokemonExplorer/PokemonExplorer.tsx
Normal 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);
|
||||
62
src/ts/app/components/PokemonExplorer/actions.ts
Normal file
62
src/ts/app/components/PokemonExplorer/actions.ts
Normal 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)));
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
144
src/ts/app/components/PokemonExplorer/reducers.ts
Normal file
144
src/ts/app/components/PokemonExplorer/reducers.ts
Normal 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;
|
||||
}
|
||||
};
|
||||
66
src/ts/app/components/PokemonExplorer/types.ts
Normal file
66
src/ts/app/components/PokemonExplorer/types.ts
Normal 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;
|
||||
}
|
||||
@ -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,
|
||||
});
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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',
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user