190 lines
6.6 KiB
TypeScript
190 lines
6.6 KiB
TypeScript
import POGOProtos from 'pogo-protos';
|
|
|
|
import React from 'react';
|
|
import { ContentRect, default as Measure } from 'react-measure';
|
|
import { FixedSizeList } from 'react-window';
|
|
|
|
import classNames from 'classnames';
|
|
|
|
import { IIndividualValues } from 'app/components/PokemonExplorer/types';
|
|
import { Grade, IStats } from 'app/models/Pokemon';
|
|
|
|
import * as styles from 'app/styles/LeagueStatsList.scss';
|
|
|
|
export interface ILeagueStatsListProps {
|
|
activePokemonId : POGOProtos.Enums.PokemonId;
|
|
activePokemonForm : POGOProtos.Enums.Form;
|
|
activeIndividualValues : IIndividualValues;
|
|
leagueStatsList : Array<IStats>;
|
|
|
|
handleActivateLeagueStats : (stats : IStats) => void;
|
|
}
|
|
|
|
interface IState {
|
|
activePokemonId : POGOProtos.Enums.PokemonId;
|
|
activePokemonForm : POGOProtos.Enums.Form;
|
|
hasSetActiveStats : boolean;
|
|
listRef : React.RefObject<FixedSizeList>;
|
|
activeIndex : number;
|
|
dimensions : {
|
|
width : number;
|
|
height : number;
|
|
};
|
|
}
|
|
|
|
interface IRowFactory {
|
|
index : number;
|
|
style : React.CSSProperties;
|
|
}
|
|
|
|
export class LeagueStatsList extends React.Component<ILeagueStatsListProps, IState> {
|
|
|
|
public static getDerivedStateFromProps(nextProps : ILeagueStatsListProps, previousState : IState) {
|
|
const nextState : IState = {
|
|
...previousState,
|
|
activePokemonId: nextProps.activePokemonId,
|
|
activePokemonForm: nextProps.activePokemonForm,
|
|
activeIndex: -1,
|
|
};
|
|
const activeIvs = nextProps.activeIndividualValues;
|
|
|
|
if (nextProps.activePokemonId !== previousState.activePokemonId || nextProps.activePokemonForm !== previousState.activePokemonForm) {
|
|
if (previousState.listRef.current !== null) {
|
|
previousState.listRef.current.scrollToItem(0);
|
|
}
|
|
|
|
} else if (activeIvs.level !== null && activeIvs.ivHp !== null && activeIvs.ivAtk !== null && activeIvs.ivDef !== null) {
|
|
let activeIndex = previousState.activeIndex;
|
|
if (activeIndex === -1) {
|
|
// there is no current index, wich means the user is entering in the IVs by hand
|
|
// now we will look through the list to see if we can find a match
|
|
nextProps.leagueStatsList.some((stats, index) => {
|
|
if (activeIvs.ivHp === stats.ivHp &&
|
|
activeIvs.ivAtk === stats.ivAtk &&
|
|
activeIvs.ivDef === stats.ivDef &&
|
|
activeIvs.level === stats.level
|
|
) {
|
|
activeIndex = index;
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
if (activeIndex > -1 && !previousState.hasSetActiveStats) {
|
|
// the current IVs belong to the stats at the active index, so scroll to active stats
|
|
if (previousState.listRef.current !== null) {
|
|
previousState.listRef.current.scrollToItem(activeIndex, 'center');
|
|
}
|
|
}
|
|
|
|
if (activeIndex === -1) {
|
|
if (previousState.listRef.current !== null) {
|
|
previousState.listRef.current.scrollToItem(0);
|
|
}
|
|
}
|
|
|
|
nextState.activeIndex = activeIndex;
|
|
}
|
|
|
|
return nextState;
|
|
}
|
|
|
|
constructor(props : ILeagueStatsListProps) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
activePokemonId: POGOProtos.Enums.PokemonId.MISSINGNO,
|
|
activePokemonForm: POGOProtos.Enums.Form.FORM_UNSET,
|
|
hasSetActiveStats: false,
|
|
listRef: React.createRef(),
|
|
activeIndex: -1,
|
|
dimensions: {
|
|
width: -1,
|
|
height: -1,
|
|
}
|
|
};
|
|
}
|
|
|
|
public render() {
|
|
const { width, height } = this.state.dimensions;
|
|
const onResize = (contentRect : ContentRect) => {
|
|
if (typeof contentRect.bounds !== 'undefined') {
|
|
this.setState({ dimensions: contentRect.bounds });
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={ styles.selectList }>
|
|
<Measure
|
|
bounds={ true }
|
|
onResize={ onResize }
|
|
>
|
|
{
|
|
({ measureRef }) => (
|
|
<div ref={ measureRef }>
|
|
<FixedSizeList
|
|
ref={ this.state.listRef }
|
|
height={ height }
|
|
itemCount={ this.props.leagueStatsList.length }
|
|
itemSize={ 35 }
|
|
width={ width }
|
|
>
|
|
{ this.rowFactory.bind(this) }
|
|
</FixedSizeList>
|
|
</div>
|
|
)
|
|
}
|
|
</Measure>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
private padString(value : string, length : number) {
|
|
let output = value;
|
|
for (let i = length - value.length; i > 0; i--) {
|
|
output += String.fromCharCode(160);
|
|
}
|
|
return output;
|
|
}
|
|
|
|
private rowFactory({ index, style } : IRowFactory) {
|
|
const activeIvs = this.props.activeIndividualValues;
|
|
const stats = this.props.leagueStatsList[index];
|
|
const css = classNames(
|
|
'list-item', // global style
|
|
styles.listItem,
|
|
{
|
|
active: activeIvs.level === stats.level &&
|
|
activeIvs.ivHp === stats.ivHp &&
|
|
activeIvs.ivAtk === stats.ivAtk &&
|
|
activeIvs.ivDef === stats.ivDef,
|
|
highlight: this.state.activeIndex === index, // this css class currently does nothing
|
|
}
|
|
);
|
|
const onClick = () => {
|
|
this.props.handleActivateLeagueStats(stats);
|
|
this.setState({
|
|
hasSetActiveStats: true,
|
|
activeIndex: index
|
|
});
|
|
};
|
|
|
|
return (
|
|
<a
|
|
key={ index }
|
|
style={ style }
|
|
className={ css }
|
|
onClick={ onClick }
|
|
>
|
|
<span>{ Grade[stats.speciesGrade] }</span>
|
|
<span>{ this.padString(stats.cp.toString(), 4) }</span>
|
|
<span>{ this.padString(stats.level.toString(), 4) }</span>
|
|
<span>{ this.padString(stats.ivHp.toString(), 2) }</span>
|
|
<span>{ this.padString(stats.ivAtk.toString(), 2) }</span>
|
|
<span>{ this.padString(stats.ivDef.toString(), 2) }</span>
|
|
</a>
|
|
);
|
|
}
|
|
}
|