Skip to content

Commit

Permalink
#18 Added Average Speed to Race Results Page
Browse files Browse the repository at this point in the history
  • Loading branch information
nickstew committed Feb 9, 2018
1 parent a399be2 commit 916fb91
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 32 deletions.
13 changes: 8 additions & 5 deletions app/actions/race.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,24 +62,27 @@ export function restartRace(id) {
};
}

export function endOngoingRace(race) {
export function endOngoingRace(race, bikeTicks) {
return {
type: END_ONGOING_RACE,
race
race,
bikeTicks
};
}

export function finishRace(race) {
export function finishRace(race, bikeTicks) {
return {
type: FINISH_ONGOING_RACE,
race
race,
bikeTicks
};
}

export function finishRacer(bikeIndex) {
export function finishRacer(bikeIndex, bikeTicks) {
return {
type: FINISH_RACER,
bikeIndex,
bikeTicks,
timestamp: moment()
};
}
23 changes: 22 additions & 1 deletion app/components/race-results/RacerDisplay.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styles from './RacerDisplay.css';
import OrdinalNumber from './OrdinalNumber';
import { getDistance, raceDuration, getSpeed } from '../../selectors';

const placementClass = (place) => {
switch (place) {
Expand Down Expand Up @@ -34,7 +35,17 @@ export default class RacerDisplay extends Component {
};

render() {
const { bikeIndex, bike, racer = {}, race, className } = this.props;
const {
bikeIndex,
bike,
racer = {},
race,
className
} = this.props;
const speed = getSpeed(
getDistance(race, bike, race.results[bikeIndex].bikeTicks),
raceDuration(race, bikeIndex)
);
const place = styles[placementClass(race.results[bikeIndex].place)];
return (
<div className={`${styles.container} ${place} col-xs-3 ${className}`}>
Expand All @@ -47,6 +58,16 @@ export default class RacerDisplay extends Component {
<OrdinalNumber place={race.results[bikeIndex].place} />
<div className={styles.box}>
<label className={styles.name}>{racer.name}</label>
<div
style={{
marginRight: '20px',
fontWeight: 'bold'
}}
className="pull-right"
>
{race.measurementSystem === 'metric' ?
`${speed.toFixed(1)} KPH` : `${speed.toFixed(1)} MPH`}
</div>
</div>
</div>
);
Expand Down
1 change: 1 addition & 0 deletions app/components/race-results/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default class RaceResults extends Component {
<div className="row">
{Object.keys(race.bikeRacerMap).map((_, i) => (
<RacerDisplay
{...this.props}
key={`RacerDisplay-${i}`}
bikeIndex={i}
bike={bikes[i]}
Expand Down
38 changes: 23 additions & 15 deletions app/components/race/Race.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,30 +41,38 @@ export default class Race extends Component {
}

componentDidMount() {
global.j5$
.subscribe((x) => {
if (!this.props.race.startTime) {
this.falseStart(x);
return;
}
const tick2complete = this.state.ticksToCompleteByBike[x];
if (tick2complete < this.state.bikeTicks[x] + 1) { return; }
const nextBikeTicks = [...this.state.bikeTicks];
const next = nextBikeTicks[x] += 1;
this.setState({ bikeTicks: nextBikeTicks });
if (tick2complete === next) { this.props.finishRacer(x); }
});
// eslint-disable-next-line react/no-did-mount-set-state
this.setState({
subscriber: global.j5$
.subscribe((x) => {
if (!this.props.race.startTime) {
this.falseStart(x);
return;
}
const tick2complete = this.state.ticksToCompleteByBike[x];
if (tick2complete < this.state.bikeTicks[x] + 1) {
return;
}
const nextBikeTicks = [...this.state.bikeTicks];
const next = nextBikeTicks[x] += 1;
this.setState({ bikeTicks: nextBikeTicks });
if (tick2complete === next) {
this.props.finishRacer(x, next);
}
})
});
}

componentWillUpdate(nextP) {
// is the race complete?
if (every(nextP.race.results, x => has(x, 'place'))) {
nextP.finishRace(nextP.race);
nextP.finishRace(nextP.race, this.state.bikeTicks);
}
}

componentWillUnmount() {
if (this.interval) { clearInterval(this.interval); }
this.state.subscriber.unsubscribe();
}

falseStart(bikeIndex) {
Expand Down Expand Up @@ -152,7 +160,7 @@ export default class Race extends Component {
<div className="col-xs-6">
<button
className="btn btn-xs btn-default"
onClick={() => callRace(race)}
onClick={() => callRace(race, bikeTicks)}
>
Call It
</button>
Expand Down
8 changes: 4 additions & 4 deletions app/containers/RacePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ function mapDispatchToProps(dispatch) {
...RaceActions,
goBack
}, dispatch),
finishRace: (race) => {
dispatch(RaceActions.finishRace(race));
finishRace: (race, bikeTicks) => {
dispatch(RaceActions.finishRace(race, bikeTicks));
dispatch(push(`/race-results/${race.id}`));
},
callRace: (race) => {
dispatch(RaceActions.endOngoingRace(race));
callRace: (race, bikeTicks) => {
dispatch(RaceActions.endOngoingRace(race, bikeTicks));
dispatch(push(`/race-results/${race.id}`));
}
};
Expand Down
10 changes: 7 additions & 3 deletions app/reducers/races.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,16 @@ export default function races(state = [], action) {
return race;
}
const nextRace = { ...race };
nextRace.results[action.bikeIndex] = getPlace(nextRace);

nextRace.results[action.bikeIndex] = {
...getPlace(nextRace),
bikeTicks: action.bikeTicks
};
return nextRace;
}
return race;
});
case FINISH_ONGOING_RACE:
// todo add bike ticks and placement for time trial race
return state.map((race) => {
if (race.current) {
return {
Expand All @@ -148,9 +151,10 @@ export default function races(state = [], action) {
return state.map((race) => {
if (race.id === action.race.id) {
const results = [...action.race.results];
const now = moment();
results.forEach((_, i) => {
if (!action.race.results[i]) {
results[i] = { place: -1 };
results[i] = { place: -1, bikeTicks: action.bikeTicks[i], finishTime: now };
}
});
return {
Expand Down
10 changes: 6 additions & 4 deletions app/selectors/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,14 @@ export const getTicksToComplete = (race, bike) =>
Math.ceil(race.raceDistance /
(race.measurementSystem === 'metric' ? 1000 : 5280) / getCircumference(race, bike));

export const raceDuration = (race, bikeIndex, now = moment()) => moment.duration(
(race.results[bikeIndex] ? race.results[bikeIndex].finishTime : now)
.diff(race.startTime, 'milliseconds')
);

export const getRaceDuration = createSelector(
[getRace, getBikeIndex, () => moment()],
(race, bikeIndex, now) => moment.duration(
(race.results[bikeIndex] ? race.results[bikeIndex].finishTime : now)
.diff(race.startTime, 'milliseconds')
)
raceDuration
);

// milliseconds in an hour multiplied by the milliseconds in race
Expand Down

0 comments on commit 916fb91

Please sign in to comment.