import React from 'react'; import Media from 'react-media'; import { connect } from 'react-redux'; import { RouteComponentProps, withRouter } from 'react-router-dom'; import classNames from 'classnames'; import { AttackTypeEffectiveness } from 'app/models/Config'; import { League } from 'app/models/League'; import { CombatMoveStats, TypeEffectiveness } from 'app/models/Pokemon'; import * as ActionsPokemonApp from 'app/actions'; import * as ActionsPokemonExplorer from 'app/components/PokemonExplorer/actions'; import { CombatMoveSelectorsOpen, IndividualValueKey, IPokemonExplorerDispatch, IPokemonExplorerStore, SelectedCombatMoves, SubNavigation, } from 'app/components/PokemonExplorer/types'; import { IRouterProps, Navigation as NavigationType } from 'app/types'; import { ExplorerLoading } from 'app/components/PokemonExplorer/ExplorerLoading'; import { LeagueIvExplorer } from 'app/components/PokemonExplorer/LeagueIvExplorer'; import { MovesExplorer } from 'app/components/PokemonExplorer/MovesExplorer'; import { Navigation } from 'app/components/PokemonExplorer/Navigation'; import { PokemonDisplay } from 'app/components/PokemonExplorer/PokemonDisplay'; import { EffectivenessMode, TypeEffectiveDisplay } from 'app/components/PokemonExplorer/TypeEffectiveDisplay'; import { appendQueryString } from 'app/utils/navigation'; import { calculateTypeCoverage } from 'app/utils/types'; import { MAX_MOBILE_WIDTH, MIN_TABLET_WIDTH } from 'common/models/constants'; import * as PVPogoProtos from 'common/models/PVPogoProtos'; import * as styles from 'app/styles/PokemonApp.scss'; interface IPokemonExplorerProps extends IRouterProps { isMenuOpen : boolean; isOverlaid : boolean; attackTypeEffectiveness : AttackTypeEffectiveness; combatMoves : CombatMoveStats; toggleInterruption : (isInterruption : boolean) => void; } interface IConnectedPokemonExplorerProps extends IPokemonExplorerStore, IPokemonExplorerDispatch, IPokemonExplorerProps {} class PokemonExplorer extends React.Component { public render() { const { isMenuOpen, isOverlaid, combatMoves, attackTypeEffectiveness, } = this.props; const { isLoading, league, individualValues, widgets, leaguePokemon, selectedCombatMoves, combatMoveSelectorsOpen, } = this.props.pokemonExplorerState; const isSelectingMove = combatMoveSelectorsOpen.quickMove || combatMoveSelectorsOpen.chargeMove1 || combatMoveSelectorsOpen.chargeMove2; const isOverlayShown = isOverlaid || isSelectingMove; const navWrapperCss = classNames( styles.navigationWrapper, ); const displayWrapperCss = classNames( styles.displayWrapper, ); const overLayCss = classNames( styles.overlay, { [styles.complete]: isSelectingMove } ); // weaknesses are indicated by types that cause super effective damage on defense const pokemonTypeWeaknesses = leaguePokemon !== null ? this.getSuperEffectiveTypes(leaguePokemon.effectiveness) : []; // strengths are indicuated by types that do super effective damage on offense const moveTypeStrengths = this.getSuperEffectiveTypes(calculateTypeCoverage(selectedCombatMoves, combatMoves, attackTypeEffectiveness)); return (
{ (leaguePokemon === null || isLoading) && } { leaguePokemon !== null && !isLoading &&
{ leaguePokemon !== null && } { widgets.types && leaguePokemon !== null &&

Type Effectivess

} { widgets.moves && leaguePokemon !== null && } { widgets.pvp && leaguePokemon !== null && }
{ isMenuOpen && }
{ isOverlayShown &&
} }
); } private readonly getSuperEffectiveTypes = (effectiveness : Map) => { const superEffectiveTypes : Array = []; Array.from(effectiveness).reduce((accumulator, currentValue) => { if (currentValue[1] > TypeEffectiveness.NEUTRAL) { accumulator.push(currentValue[0]); } return accumulator; }, superEffectiveTypes); return superEffectiveTypes; } 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(isOpen); } private readonly handleOverlayClick = () => { this.props.dispatch(ActionsPokemonExplorer.setCombatMoveSelectorsOpen({ quickMove: false, chargeMove1: false, chargeMove2: false, })); this.props.toggleInterruption(false); } private readonly handleNavigationClick = (widget : SubNavigation | NavigationType) => { if (widget === 'pokedex') { this.props.dispatch(ActionsPokemonApp.setIsInterruption(true)); this.props.dispatch(ActionsPokemonApp.setNavigation('pokedex')); } else if (widget !== 'menu') { this.props.dispatch(ActionsPokemonExplorer.setSubNavigationWidgetIsShown(widget, !this.props.pokemonExplorerState.widgets[widget])); } } 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, }; }; export const ConnectedPokemonExplorer = withRouter(connect(mapStateToProps, mapDispatchToProps, mergeProps)(PokemonExplorer));