@@ -138,7 +118,7 @@ class DashboardView extends BaseView {
+ scores={this.props.fraggersOfTheMonth} />
@@ -146,14 +126,29 @@ class DashboardView extends BaseView {
+ scores={this.props.emosOfTheMonth} />
-
@@ -44,4 +44,8 @@ class ErrorView extends React.Component {
}
}
+ErrorView.propTypes = {
+ params: React.PropTypes.object
+};
+
export default ErrorView;
diff --git a/frontend/src/views/NavigationBarView.js b/frontend/src/views/NavigationBarView.js
index 45dd004..d685171 100644
--- a/frontend/src/views/NavigationBarView.js
+++ b/frontend/src/views/NavigationBarView.js
@@ -25,15 +25,19 @@ import ContainerComponent from "../components/ContainerComponent";
import Glyphicon from "react-bootstrap/lib/Glyphicon";
import React from "react";
import Navbar from "react-bootstrap/lib/Navbar";
+import {connect} from "react-redux";
import {Router, Link} from "react-router";
-import reduxStore from "../store";
+import {
+ cleanup, expand, collapse, showAboutModal, hideAboutModal, showSettingsModal,
+ hideSettingsModal
+} from "../actions/navigationBar";
import {LAYOUT_WIDE} from "../lib/defs";
import AboutModalView from "./AboutModalView";
import SettingsModalView from "./SettingsModalView";
-class NavigationBarItemView extends React.Component {
+class NavigationBarItemView extends React.PureComponent {
render () {
let className = ClassNames({
active: this.props.active
@@ -56,66 +60,46 @@ NavigationBarItemView.propTypes = {
onClick: React.PropTypes.func.isRequired
};
-class NavigationBarView extends React.Component {
+class NavigationBarView extends React.PureComponent {
constructor (props) {
super(props);
this.onNavigationBarItemClick = this.onNavigationBarItemClick.bind(this);
this.onNavigationBarToggleExpanded = this.onNavigationBarToggleExpanded.bind(this);
this.onHideSettingsModal = this.onHideSettingsModal.bind(this);
this.onShowSettingsModalButtonClick = this.onShowSettingsModalButtonClick.bind(this);
- this.onStoreChange = this.onStoreChange.bind(this);
this.onHideAboutModal = this.onHideAboutModal.bind(this);
this.onShowAboutModalButtonClick = this.onShowAboutModalButtonClick.bind(this);
-
- this.state = {
- layout: reduxStore.getState().settings.layout,
- navBarExpanded: false,
- showAboutModal: false,
- showSettingsModal: false
- };
- }
- componentDidMount () {
- this._storeUnsubscribe = reduxStore.subscribe(this.onStoreChange);
- }
- componentWillUnmount () {
- this._storeUnsubscribe();
}
onNavigationBarItemClick (e) {
- this.setState({navBarExpanded: false});
+ this.props.dispatch(collapse());
}
onNavigationBarToggleExpanded (expanded) {
- this.setState({navBarExpanded: expanded});
- }
- onHideSettingsModal () {
- this.setState({showSettingsModal: false});
+ if (expanded) {
+ this.props.dispatch(expand());
+ } else {
+ this.props.dispatch(collapse());
+ }
}
onShowSettingsModalButtonClick () {
- this.setState({
- navBarExpanded: false,
- showSettingsModal: true
- });
+ this.props.dispatch(showSettingsModal());
}
- onStoreChange () {
- this.setState({layout: reduxStore.getState().settings.layout});
- }
- onHideAboutModal () {
- this.setState({showAboutModal: false});
+ onHideSettingsModal () {
+ this.props.dispatch(hideSettingsModal());
}
onShowAboutModalButtonClick () {
- this.setState({
- navBarExpanded: false,
- showAboutModal: true
- });
+ this.props.dispatch(showAboutModal());
+ }
+ onHideAboutModal () {
+ this.props.dispatch(hideAboutModal());
}
render () {
return (
@@ -160,20 +144,38 @@ class NavigationBarView extends React.Component {
-
-
+
+
);
}
}
-NavigationBarView.PropTypes = {
- router: React.PropTypes.instanceOf(Router).isRequired
+NavigationBarView.propTypes = {
+ expanded: React.PropTypes.bool.isRequired,
+ layout: React.PropTypes.string.isRequired,
+ location: React.PropTypes.object.isRequired,
+ router: React.PropTypes.object.isRequired,
+ showAboutModal: React.PropTypes.bool.isRequired,
+ showSettingsModal: React.PropTypes.bool.isRequired
};
-export default NavigationBarView;
+const mapStateToProps = (state, props) => {
+ return {
+ expanded: state.navigationBar.expanded,
+ layout: state.settings.layout,
+ location: props.location,
+ router: props.router,
+ showAboutModal: state.navigationBar.showAboutModal,
+ showSettingsModal: state.navigationBar.showSettingsModal
+ };
+};
+
+const reduxContainer = connect(mapStateToProps)(NavigationBarView);
+
+export default reduxContainer;
diff --git a/frontend/src/views/PlayerGameView.js b/frontend/src/views/PlayerGameView.js
index c5e96d9..0cc4fff 100644
--- a/frontend/src/views/PlayerGameView.js
+++ b/frontend/src/views/PlayerGameView.js
@@ -21,17 +21,18 @@
*/
import React from "react";
+import {connect} from "react-redux";
import underscore from "underscore";
-import BaseView from "../lib/BaseView";
import ChartComponent from "../components/ChartComponent";
import ContainerComponent from "../components/ContainerComponent";
import ItemIconComponent from "../components/ItemIconComponent";
import LoaderComponent from "../components/LoaderComponent";
import PowerupIconComponent from "../components/PowerupIconComponent";
import WeaponIconComponent from "../components/WeaponIconComponent";
+import {cleanup, loadData} from "../actions/playerGame";
-class PlayerGameView extends BaseView {
+class PlayerGameView extends React.PureComponent {
constructor (props) {
super(props);
@@ -40,87 +41,39 @@ class PlayerGameView extends BaseView {
"enabled": false
}
};
-
- this.state = {
- ready: false,
- map: "",
- weaponStats: {},
- itemStats: {},
- powerupStats: {},
- scoreChartSeries: [],
- damageChartSeries: [],
- totalsChartSeries: []
- };
}
componentDidMount () {
- let url = (
- "/api/v1/players/" + this.props.params.player + "/game/" +
- this.props.params.game
- );
-
- this.fetch(url).then((data) => {
- this.setState({
- ready: true,
- map: data.map,
- weaponStats: data.weapons || {},
- itemStats: data.items || {},
- powerupStats: data.powerups || {}
- });
-
- this.loadChartsData();
- });
+ this.props.dispatch(loadData(
+ this.props.dispatch, this.props.params.player, this.props.params.game
+ ));
}
- processSerieData (serie, name) {
- if (!serie) {
- return [];
- }
-
- return [
- {
- "type": "pie",
- "name": name,
- "data": serie
- }
- ];
- }
- loadChartsData () {
- let url = (
- "/api/v1/charts/player/" + this.props.params.player + "/game/" +
- this.props.params.game
- );
-
- this.fetch(url).then((data) => {
- this.setState({
- scoreChartSeries: this.processSerieData(data.score),
- damageChartSeries: this.processSerieData(data.damage),
- totalsChartSeries: this.processSerieData(data.totals)
- });
- });
+ componentWillUnmount () {
+ this.props.dispatch(cleanup());
}
render () {
return (
- {this.props.params.player} stats on {this.state.map}
+ {this.props.params.player} stats on {this.props.map}
@@ -139,15 +92,15 @@ class PlayerGameView extends BaseView {
- {underscore.keys(this.state.weaponStats).length == 0 &&
+ {underscore.keys(this.props.weaponStats).length == 0 &&
No stats :( |
}
{underscore.map(
- underscore.keys(this.state.weaponStats), (key, index) => {
- let stats = this.state.weaponStats[key];
+ underscore.keys(this.props.weaponStats), (key, index) => {
+ let stats = this.props.weaponStats[key];
return (
@@ -176,15 +129,15 @@ class PlayerGameView extends BaseView {
- {underscore.keys(this.state.itemStats).length == 0 &&
+ {underscore.keys(this.props.itemStats).length == 0 &&
No stats :( |
}
{underscore.map(
- underscore.keys(this.state.itemStats), (key, index) => {
- let value = this.state.itemStats[key];
+ underscore.keys(this.props.itemStats), (key, index) => {
+ let value = this.props.itemStats[key];
return (
@@ -211,15 +164,15 @@ class PlayerGameView extends BaseView {
- {underscore.keys(this.state.powerupStats).length == 0 &&
+ {underscore.keys(this.props.powerupStats).length == 0 &&
No stats :( |
}
{underscore.map(
- underscore.keys(this.state.powerupStats), (key, index) => {
- let stats = this.state.powerupStats[key];
+ underscore.keys(this.props.powerupStats), (key, index) => {
+ let stats = this.props.powerupStats[key];
return (
@@ -235,10 +188,38 @@ class PlayerGameView extends BaseView {
-
+
);
}
}
-export default PlayerGameView;
+PlayerGameView.propTypes = {
+ loading: React.PropTypes.bool.isRequired,
+ map: React.PropTypes.string.isRequired,
+ weaponStats: React.PropTypes.object.isRequired,
+ itemStats: React.PropTypes.object.isRequired,
+ powerupStats: React.PropTypes.object.isRequired,
+ scoreChartSeries: React.PropTypes.array.isRequired,
+ damageChartSeries: React.PropTypes.array.isRequired,
+ totalsChartSeries: React.PropTypes.array.isRequired,
+ params: React.PropTypes.object.isRequired
+};
+
+const mapStateToProps = (state, props) => {
+ return {
+ loading: state.playerGame.loading,
+ map: state.playerGame.map,
+ weaponStats: state.playerGame.weaponStats,
+ itemStats: state.playerGame.itemStats,
+ powerupStats: state.playerGame.powerupStats,
+ scoreChartSeries: state.playerGame.scoreChartSeries,
+ damageChartSeries: state.playerGame.damageChartSeries,
+ totalsChartSeries: state.playerGame.totalsChartSeries,
+ params: props.params
+ };
+};
+
+const reduxContainer = connect(mapStateToProps)(PlayerGameView);
+
+export default reduxContainer;
diff --git a/frontend/src/views/PlayerStatsView.js b/frontend/src/views/PlayerStatsView.js
index fce69fa..308b738 100644
--- a/frontend/src/views/PlayerStatsView.js
+++ b/frontend/src/views/PlayerStatsView.js
@@ -22,16 +22,18 @@
import ClassName from "classnames";
import React from "react";
+import {connect} from "react-redux";
+import underscore from "underscore";
-import BaseView from "../lib/BaseView";
import ChartComponent from "../components/ChartComponent";
+import {cleanup, loadChartData, setMode} from "../actions/playerStats";
const WINS_CHART_TITLE_SESSION = "Wins and losses by session";
const WINS_CHART_TITLE_MAP = "Wins and losses by map";
const ACCURACY_CHART_TITLE_SESSION = "Average weapon accuracy by session";
const ACCURACY_CHART_TITLE_MAP = "Average weapon accuracy by map";
-class ModeLinkComponent extends React.Component {
+class ModeLinkComponent extends React.PureComponent {
constructor (props) {
super(props);
this.onClick = this.onClick.bind(this);
@@ -62,80 +64,55 @@ ModeLinkComponent.propTypes = {
onSwitchMode: React.PropTypes.func.isRequired
};
-class BaseStatsChartComponent extends BaseView {
+class BaseStatsChartComponent extends React.PureComponent {
constructor (props) {
super(props);
this.chartConfig = {};
-
- this.state = {
- sessionCategories: [],
- sessionSeries: [],
- mapCategories: [],
- mapSeries: []
- };
}
componentDidMount () {
this.load();
}
- componentWillReceiveProps (nextProps) {
- if (nextProps.player != this.props.player) {
- this.setState({
- sessionCategories: [],
- sessionSeries: [],
- mapCategories: [],
- mapSeries: []
- });
- }
- }
componentDidUpdate (prevProps, prevState) {
- if (prevProps.player != this.props.player || prevProps.mode != this.props.mode) {
+ if (prevProps.player != this.props.player) {
+ this.load(true);
+ } else if (prevProps.mode != this.props.mode) {
this.load();
}
}
- url () {
+ kind () {
throw new Error("Not Implemented");
}
- parse () {
- throw new Error("Not Implemented");
- }
- load () {
- let hasData = true;
- if (this.props.mode == "session") {
- hasData = hasData && this.state.sessionCategories.length > 0;
- hasData = hasData && this.state.sessionSeries.length > 0;
- } else {
- hasData = hasData && this.state.mapCategories.length > 0;
- hasData = hasData && this.state.mapSeries.length > 0;
+ load (force) {
+ if (underscore.isUndefined(force)) {
+ force = false;
}
- if (!hasData) {
- this.fetch(this.url()).then((data) => {
- let newState = {};
- let parsedData = this.parse(data);
+ let hasData = true;
+ if (this.props.mode == "session") {
+ hasData = hasData && this.props.sessionData.categories.length > 0;
+ hasData = hasData && this.props.sessionData.series.length > 0;
+ } else {
+ hasData = hasData && this.props.mapData.categories.length > 0;
+ hasData = hasData && this.props.mapData.series.length > 0;
+ }
- if (this.props.mode == "session") {
- newState.sessionCategories = parsedData.categories;
- newState.sessionSeries = parsedData.series;
- } else {
- newState.mapCategories = parsedData.categories;
- newState.mapSeries = parsedData.series;
- }
-
- this.setState(newState);
- });
+ if (force || !hasData) {
+ this.props.dispatch(loadChartData(
+ this.props.dispatch, this.props.player, this.kind(), this.props.mode
+ ));
}
}
title () {
throw new Error("Not Implemented");
}
render () {
- let categories = this.state.sessionCategories;
- let series = this.state.sessionSeries;
+ let categories = this.props.sessionData.categories;
+ let series = this.props.sessionData.series;
if (this.props.mode == "map") {
- categories = this.state.mapCategories;
- series = this.state.mapSeries;
+ categories = this.props.mapData.categories;
+ series = this.props.mapData.series;
}
return (
@@ -188,27 +165,8 @@ class WinsChartComponent extends BaseStatsChartComponent {
}
};
}
- url () {
- return (
- "/api/v1/charts/player/" + this.props.player + "/wins/" + this.props.mode
- );
- }
- parse (data) {
- let result = {
- categories: [],
- series: [
- {"name": "Wins", "data": data.wins},
- {"name": "Losses", "data": data.losses}
- ]
- };
-
- if (this.props.mode == "session") {
- result.categories = data.dates;
- } else {
- result.categories = data.maps;
- }
-
- return result;
+ kind () {
+ return "wins";
}
title () {
if (this.props.mode == "map") {
@@ -222,6 +180,13 @@ class WinsChartComponent extends BaseStatsChartComponent {
}
}
+WinsChartComponent.propTypes = {
+ player: React.PropTypes.string.isRequired,
+ mode: React.PropTypes.string.isRequired,
+ sessionData: React.PropTypes.object.isRequired,
+ mapData: React.PropTypes.object.isRequired
+};
+
class AccuracyChartComponent extends BaseStatsChartComponent {
constructor (props) {
super(props);
@@ -241,25 +206,8 @@ class AccuracyChartComponent extends BaseStatsChartComponent {
}
};
}
- url () {
- return (
- "/api/v1/charts/player/" + this.props.player + "/accuracy/" +
- this.props.mode
- );
- }
- parse (data) {
- let result = {
- categories: [],
- series: data.series
- };
-
- if (this.props.mode == "session") {
- result.categories = data.dates;
- } else {
- result.categories = data.maps;
- }
-
- return result;
+ kind () {
+ return "accuracy";
}
title () {
if (this.props.mode == "map") {
@@ -273,25 +221,28 @@ class AccuracyChartComponent extends BaseStatsChartComponent {
}
}
-WinsChartComponent.propTypes = {
+AccuracyChartComponent.propTypes = {
player: React.PropTypes.string.isRequired,
- mode: React.PropTypes.string.isRequired
+ mode: React.PropTypes.string.isRequired,
+ sessionData: React.PropTypes.object.isRequired,
+ mapData: React.PropTypes.object.isRequired
};
-class PlayerStatsView extends React.Component {
+class PlayerStatsView extends React.PureComponent {
constructor (props) {
super(props);
this.onSwitchMode = this.onSwitchMode.bind(this);
-
- this.state = {
- mode: "session"
- };
}
componentWillReceiveProps (nextProps) {
- this.setState({mode: "session"});
+ if (nextProps.params.player != this.props.params.player) {
+ this.props.dispatch(cleanup());
+ }
}
onSwitchMode (mode) {
- this.setState({mode: mode});
+ this.props.dispatch(setMode(mode));
+ }
+ componentWillUnmount () {
+ this.props.dispatch(cleanup());
}
render () {
return (
@@ -300,13 +251,13 @@ class PlayerStatsView extends React.Component {
@@ -314,16 +265,42 @@ class PlayerStatsView extends React.Component {
+ mode={this.props.mode}
+ sessionData={this.props.sessionWinsChartData}
+ mapData={this.props.mapWinsChartData}
+ dispatch={this.props.dispatch} />
+ mode={this.props.mode}
+ sessionData={this.props.sessionAccuracyChartData}
+ mapData={this.props.mapAccuracyChartData}
+ dispatch={this.props.dispatch} />
);
}
}
-export default PlayerStatsView;
+PlayerStatsView.propTypes = {
+ mode: React.PropTypes.string.isRequired,
+ sessionWinsChartData: React.PropTypes.object.isRequired,
+ mapWinsChartData: React.PropTypes.object.isRequired,
+ sessionAccuracyChartData: React.PropTypes.object.isRequired,
+ mapAccuracyChartData: React.PropTypes.object.isRequired,
+ params: React.PropTypes.object.isRequired
+};
+
+const mapStateToProps = (state, props) => {
+ return {
+ mode: state.playerStats.mode,
+ sessionWinsChartData: state.playerStats.sessionWinsChartData,
+ mapWinsChartData: state.playerStats.mapWinsChartData,
+ sessionAccuracyChartData: state.playerStats.sessionAccuracyChartData,
+ mapAccuracyChartData: state.playerStats.mapAccuracyChartData,
+ params: props.params
+ };
+};
+
+const reduxContainer = connect(mapStateToProps)(PlayerStatsView);
+
+export default reduxContainer;
diff --git a/frontend/src/views/PlayersView.js b/frontend/src/views/PlayersView.js
index 6349e32..d7883c6 100644
--- a/frontend/src/views/PlayersView.js
+++ b/frontend/src/views/PlayersView.js
@@ -23,13 +23,14 @@
import ClassName from "classnames";
import React from "react";
import {Link} from "react-router";
+import {connect} from "react-redux";
-import BaseView from "../lib/BaseView";
import ContainerComponent from "../components/ContainerComponent";
import LoaderComponent from "../components/LoaderComponent";
import PlayerStatsView from "./PlayerStatsView";
+import {cleanup, loadData} from "../actions/players";
-class PlayerLinkComponent extends React.Component {
+class PlayerLinkComponent extends React.PureComponent {
render () {
let className = ClassName({
active: this.props.active
@@ -48,22 +49,12 @@ PlayerLinkComponent.propTypes = {
player: React.PropTypes.string.isRequired
};
-class PlayersView extends BaseView {
- constructor (props) {
- super(props);
-
- this.state = {
- ready: false,
- players: []
- };
- }
+class PlayersView extends React.PureComponent {
componentDidMount () {
- this.fetch("/api/v1/players").then((data) => {
- this.setState({
- ready: true,
- players: data.players
- });
- });
+ this.props.dispatch(loadData(this.props.dispatch));
+ }
+ componentWillUnmount () {
+ this.props.dispatch(cleanup());
}
render () {
return (
@@ -72,7 +63,7 @@ class PlayersView extends BaseView {
Players
- {this.state.players.map((item, index) => {
+ {this.props.players.map((item, index) => {
return (
-
+
);
}
}
-export default PlayersView;
+PlayersView.propTypes = {
+ loading: React.PropTypes.bool.isRequired,
+ players: React.PropTypes.array.isRequired,
+ params: React.PropTypes.object.isRequired
+};
+
+const mapStateToProps = (state, props) => {
+ return {
+ loading: state.players.loading,
+ players: state.players.players,
+ params: props.params
+ };
+};
+
+const reduxContainer = connect(mapStateToProps)(PlayersView);
+
+export default reduxContainer;
+
diff --git a/frontend/src/views/SessionsView.js b/frontend/src/views/SessionsView.js
index 3d08f35..9461d5a 100644
--- a/frontend/src/views/SessionsView.js
+++ b/frontend/src/views/SessionsView.js
@@ -22,15 +22,16 @@
import ClassName from "classnames";
import React from "react";
+import {connect} from "react-redux";
import {Link} from "react-router";
-import BaseView from "../lib/BaseView";
import ChartComponent from "../components/ChartComponent";
import ContainerComponent from "../components/ContainerComponent";
import LoaderComponent from "../components/LoaderComponent";
import WeaponIconComponent from "../components/WeaponIconComponent";
+import {cleanup, setDay} from "../actions/sessions";
-class NavComponent extends React.Component {
+class NavComponent extends React.PureComponent {
render () {
let previousClassName = ClassName("previous", {
disabled: !this.props.previousDay
@@ -64,7 +65,7 @@ NavComponent.propTypes = {
nextDay: React.PropTypes.string
};
-class GamesTableView extends React.Component {
+class GamesTableView extends React.PureComponent {
render () {
return (
@@ -136,7 +137,7 @@ GamesTableView.propTypes = {
games: React.PropTypes.array.isRequired
};
-class SessionsView extends BaseView {
+class SessionsView extends React.PureComponent {
constructor (props) {
super(props);
@@ -163,96 +164,80 @@ class SessionsView extends BaseView {
}
}
};
-
- this.state = {
- shouldReload: false,
- ready: false,
- day: "",
- previousDay: "",
- nextDay: "",
- games: [],
- categories: null,
- series: []
- };
+ }
+ setDay (day) {
+ this.props.dispatch(setDay(this.props.dispatch, day));
}
componentDidMount () {
- this.loadData();
+ this.setDay(this.props.params.day);
+ }
+ componentWillUnmount () {
+ this.props.dispatch(cleanup());
}
componentDidUpdate (prevProps) {
- if ((this.state.shouldReload) && (!this.state.ready)) {
- this.setState({shouldReload: false});
- this.loadData();
+ if (prevProps.params.day != this.props.params.day) {
+ this.setDay(this.props.params.day);
}
}
- componentWillReceiveProps (nextProps) {
- if (nextProps.params.day != this.props.params.day) {
- this.setState({
- shouldReload: true,
- ready: false,
- day: "",
- previousDay: "",
- nextDay: "",
- games: [],
- categories: null,
- series: []
- });
- }
- }
- loadData () {
- this.fetch("/api/v1/sessions/" + (this.props.params.day || "")).then((data) => {
- this.setState({
- shouldReload: false,
- ready: true,
- day: data.day,
- previousDay: data.previous_day,
- nextDay: data.next_day,
- games: data.games
- });
-
- this.loadChartData();
- });
- }
- loadChartData () {
- this.fetch("/api/v1/charts/day/" + this.state.day).then((data) => {
- this.setState({
- categories: data.maps,
- series: data.scores
- });
- });
- }
render () {
return (
- {this.state.ready &&
+ {!this.props.loading &&
+ previousDay={this.props.previousDay}
+ nextDay={this.props.nextDay} />
Results
+ categories={this.props.categories}
+ series={this.props.series}
+ subtitle={this.props.day} />
Stats
+ games={this.props.games} />
+ previousDay={this.props.previousDay}
+ nextDay={this.props.nextDay} />
}
-
+
);
}
}
-export default SessionsView;
+SessionsView.propTypes = {
+ categories: React.PropTypes.array.isRequired,
+ day: React.PropTypes.string.isRequired,
+ games: React.PropTypes.array.isRequired,
+ loading: React.PropTypes.bool.isRequired,
+ nextDay: React.PropTypes.string.isRequired,
+ params: React.PropTypes.object.isRequired,
+ previousDay: React.PropTypes.string.isRequired,
+ series: React.PropTypes.array.isRequired
+};
+
+const mapStateToProps = (state, props) => {
+ return {
+ loading: state.sessions.loading,
+ day: state.sessions.day,
+ previousDay: state.sessions.previousDay,
+ nextDay: state.sessions.nextDay,
+ games: state.sessions.games,
+ categories: state.sessions.categories,
+ series: state.sessions.series,
+ params: props.params
+ };
+};
+
+const reduxContainer = connect(mapStateToProps)(SessionsView);
+
+export default reduxContainer;
diff --git a/frontend/src/views/SettingsModalView.js b/frontend/src/views/SettingsModalView.js
index d3c1bae..2bf3313 100644
--- a/frontend/src/views/SettingsModalView.js
+++ b/frontend/src/views/SettingsModalView.js
@@ -29,10 +29,12 @@ import Modal from "react-bootstrap/lib/Modal";
import React from "react";
import {connect} from "react-redux";
-import {DEFAULT_LAYOUT, LAYOUT_CHOICES, SETTINGS_KEY_LAYOUT} from "../lib/defs";
+import {
+ DEFAULT_LAYOUT, LAYOUT_CHOICES, SETTINGS_KEY_LAYOUT
+} from "../lib/defs";
import {setLayout} from "../actions/settings";
-class SettingsModalView extends React.Component {
+class SettingsModalView extends React.PureComponent {
constructor (props) {
super(props);
this.onSaveButtonClick = this.onSaveButtonClick.bind(this);
@@ -42,16 +44,15 @@ class SettingsModalView extends React.Component {
layout: this.props.settings.layout
};
}
+ componentWillReceiveProps (nextProps) {
+ if (!this.props.show && nextProps.show) {
+ this.setState({layout: this.props.settings.layout});
+ }
+ }
onSaveButtonClick (e) {
e.stopPropagation();
e.preventDefault();
- try {
- window.localStorage.setItem(SETTINGS_KEY_LAYOUT, this.state.layout);
- } catch (error) {
- // pass
- }
-
this.props.dispatch(setLayout(this.state.layout));
this.props.onHide();
@@ -95,7 +96,6 @@ class SettingsModalView extends React.Component {
}
SettingsModalView.PropTypes = {
- dispatch: React.PropTypes.func.isRequired,
settings: React.PropTypes.object.isRequired,
show: React.PropTypes.bool.isRequired,
onHide: React.PropTypes.func.isRequired
diff --git a/q3stats/web_app/blueprints/api_v1/views/players.py b/q3stats/web_app/blueprints/api_v1/views/players.py
index aa32e95..7ec5f55 100644
--- a/q3stats/web_app/blueprints/api_v1/views/players.py
+++ b/q3stats/web_app/blueprints/api_v1/views/players.py
@@ -92,6 +92,8 @@ def get_api_v1_player_game(player, game_uuid):
abort(404)
result = {
+ "game": game_uuid,
+ "player": player,
"map": game.map,
"items": score.items,
"weapons": _process_weapons(score.weapons),
diff --git a/tests_web_app/test_get_api_v1_player_game.py b/tests_web_app/test_get_api_v1_player_game.py
index db0861f..75cac51 100644
--- a/tests_web_app/test_get_api_v1_player_game.py
+++ b/tests_web_app/test_get_api_v1_player_game.py
@@ -86,6 +86,8 @@ class Test_GetAPIv1Players(BaseQ3StatsWebAppTestCase):
rsp = self.client.get('/api/v1/players/Player 1/game/game1')
assert rsp.status_code == 200
+ assert rsp.json['game'] == 'game1'
+ assert rsp.json['player'] == 'Player 1'
assert rsp.json['map'] == 'Q3DM7'
assert rsp.json['items'] == {'YA': 1}
diff --git a/tests_web_app/tmp/.placeholder b/tests_web_app/tmp/.placeholder
new file mode 100644
index 0000000..e69de29