summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoffrey Bion <joffrey.bion@gmail.com>2017-05-28 21:32:36 +0200
committerGitHub <noreply@github.com>2017-05-28 21:32:36 +0200
commitba9cd259ed1ca2370565265eab9fe2628ad6502c (patch)
tree0c24821770274a414f80b3092d5be54902c042d9
parentFix proxy not working since CRA upgrade (diff)
parentMove to immutable with Records (diff)
downloadseven-wonders-ba9cd259ed1ca2370565265eab9fe2628ad6502c.tar.gz
seven-wonders-ba9cd259ed1ca2370565265eab9fe2628ad6502c.tar.bz2
seven-wonders-ba9cd259ed1ca2370565265eab9fe2628ad6502c.zip
Merge pull request #14 from luxons/immutable
Move to immutable with Records
-rw-r--r--frontend/flow-typed/npm/redux-immutable_vx.x.x.js74
-rw-r--r--frontend/package.json4
-rw-r--r--frontend/src/components/gameList.js9
-rw-r--r--frontend/src/components/playerList.js5
-rw-r--r--frontend/src/containers/gameBrowser.js4
-rw-r--r--frontend/src/containers/lobby.js7
-rw-r--r--frontend/src/models/errors.js34
-rw-r--r--frontend/src/models/games.js41
-rw-r--r--frontend/src/models/players.js26
-rw-r--r--frontend/src/reducers.js3
-rw-r--r--frontend/src/redux/app.js2
-rw-r--r--frontend/src/redux/errors.js22
-rw-r--r--frontend/src/redux/games.js29
-rw-r--r--frontend/src/redux/players.js21
-rw-r--r--frontend/src/store.js4
-rw-r--r--frontend/yarn.lock8
16 files changed, 222 insertions, 71 deletions
diff --git a/frontend/flow-typed/npm/redux-immutable_vx.x.x.js b/frontend/flow-typed/npm/redux-immutable_vx.x.x.js
new file mode 100644
index 00000000..7bc76710
--- /dev/null
+++ b/frontend/flow-typed/npm/redux-immutable_vx.x.x.js
@@ -0,0 +1,74 @@
+// flow-typed signature: f0465fe5b273048a19e890db9b35b2e6
+// flow-typed version: <<STUB>>/redux-immutable_v^4.0.0/flow_v0.46.0
+
+/**
+ * This is an autogenerated libdef stub for:
+ *
+ * 'redux-immutable'
+ *
+ * Fill this stub out by replacing all the `any` types.
+ *
+ * Once filled out, we encourage you to share your work with the
+ * community by sending a pull request to:
+ * https://github.com/flowtype/flow-typed
+ */
+
+declare module 'redux-immutable' {
+ declare module.exports: any;
+}
+
+/**
+ * We include stubs for each file inside this npm package in case you need to
+ * require those files directly. Feel free to delete any files that aren't
+ * needed.
+ */
+declare module 'redux-immutable/benchmarks/index' {
+ declare module.exports: any;
+}
+
+declare module 'redux-immutable/dist/combineReducers' {
+ declare module.exports: any;
+}
+
+declare module 'redux-immutable/dist/index' {
+ declare module.exports: any;
+}
+
+declare module 'redux-immutable/dist/utilities/getStateName' {
+ declare module.exports: any;
+}
+
+declare module 'redux-immutable/dist/utilities/getUnexpectedInvocationParameterMessage' {
+ declare module.exports: any;
+}
+
+declare module 'redux-immutable/dist/utilities/index' {
+ declare module.exports: any;
+}
+
+declare module 'redux-immutable/dist/utilities/validateNextState' {
+ declare module.exports: any;
+}
+
+// Filename aliases
+declare module 'redux-immutable/benchmarks/index.js' {
+ declare module.exports: $Exports<'redux-immutable/benchmarks/index'>;
+}
+declare module 'redux-immutable/dist/combineReducers.js' {
+ declare module.exports: $Exports<'redux-immutable/dist/combineReducers'>;
+}
+declare module 'redux-immutable/dist/index.js' {
+ declare module.exports: $Exports<'redux-immutable/dist/index'>;
+}
+declare module 'redux-immutable/dist/utilities/getStateName.js' {
+ declare module.exports: $Exports<'redux-immutable/dist/utilities/getStateName'>;
+}
+declare module 'redux-immutable/dist/utilities/getUnexpectedInvocationParameterMessage.js' {
+ declare module.exports: $Exports<'redux-immutable/dist/utilities/getUnexpectedInvocationParameterMessage'>;
+}
+declare module 'redux-immutable/dist/utilities/index.js' {
+ declare module.exports: $Exports<'redux-immutable/dist/utilities/index'>;
+}
+declare module 'redux-immutable/dist/utilities/validateNextState.js' {
+ declare module.exports: $Exports<'redux-immutable/dist/utilities/validateNextState'>;
+}
diff --git a/frontend/package.json b/frontend/package.json
index 7278ded0..e7701703 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -10,6 +10,7 @@
"react-scripts": "1.0.5"
},
"dependencies": {
+ "immutable": "^3.8.1",
"normalizr": "^3.2.3",
"react": "^15.5.4",
"react-dom": "^15.5.4",
@@ -19,12 +20,11 @@
"react-router-redux": "^4.0.8",
"rebass": "^0.3.3",
"redux": "^3.6.0",
+ "redux-immutable": "^4.0.0",
"redux-saga": "^0.13.0",
"redux-saga-router": "^2.1.0",
- "redux-seamless-immutable": "^0.3.0",
"reflexbox": "^2.2.3",
"reselect": "^3.0.1",
- "seamless-immutable": "^7.1.2",
"sockjs-client": "^1.1.4",
"webstomp-client": "^1.0.6"
},
diff --git a/frontend/src/components/gameList.js b/frontend/src/components/gameList.js
index f3a0d381..17dad16f 100644
--- a/frontend/src/components/gameList.js
+++ b/frontend/src/components/gameList.js
@@ -1,18 +1,15 @@
import React from 'react';
import { Flex } from 'reflexbox';
import { Text, Space, Button } from 'rebass';
-import Immutable from 'seamless-immutable';
-const GameList = props => (
+const GameList = ({ games, joinGame }) => (
<div>
- {Immutable.asMutable(props.games).map((game, index) => {
- const joinGame = () => props.joinGame(game.id);
-
+ {games.map((game, index) => {
return (
<Flex key={index}>
<Text>{game.name}</Text>
<Space auto />
- <Button onClick={joinGame}>Join</Button>
+ <Button onClick={() => joinGame(game.id)}>Join</Button>
</Flex>
);
})}
diff --git a/frontend/src/components/playerList.js b/frontend/src/components/playerList.js
index 1a68b067..bc2c768e 100644
--- a/frontend/src/components/playerList.js
+++ b/frontend/src/components/playerList.js
@@ -1,11 +1,10 @@
import React from 'react';
import { Flex } from 'reflexbox';
import { Text } from 'rebass';
-import Immutable from 'seamless-immutable';
-const PlayerList = props => (
+const PlayerList = ({ players }) => (
<div>
- {Immutable.asMutable(props.players).map(player => {
+ {players.map(player => {
return (
<Flex key={player.index}>
<Text>{player.displayName}</Text>
diff --git a/frontend/src/containers/gameBrowser.js b/frontend/src/containers/gameBrowser.js
index 643dbebc..ac3f1504 100644
--- a/frontend/src/containers/gameBrowser.js
+++ b/frontend/src/containers/gameBrowser.js
@@ -41,8 +41,8 @@ class GameBrowser extends Component {
}
const mapStateToProps = state => ({
- currentPlayer: getCurrentPlayer(state) || { displayName: '[ERROR]' },
- games: getAllGames(state),
+ currentPlayer: getCurrentPlayer(state.get('players')),
+ games: getAllGames(state.get('games')),
});
const mapDispatchToProps = {
diff --git a/frontend/src/containers/lobby.js b/frontend/src/containers/lobby.js
index 90714aec..fc762056 100644
--- a/frontend/src/containers/lobby.js
+++ b/frontend/src/containers/lobby.js
@@ -1,6 +1,6 @@
import React, { Component } from 'react';
+import { List } from 'immutable';
import { connect } from 'react-redux';
-import Immutable from 'seamless-immutable';
import { Button } from 'rebass';
import PlayerList from '../components/playerList';
@@ -28,10 +28,11 @@ class Lobby extends Component {
}
const mapStateToProps = state => {
- const game = getCurrentGame(state);
+ const game = getCurrentGame(state.get('games'));
+ console.info(game);
return {
currentGame: game,
- players: game ? getPlayers(state, game.players) : Immutable([]),
+ players: game ? getPlayers(state.get('players'), game.players) : new List(),
};
};
diff --git a/frontend/src/models/errors.js b/frontend/src/models/errors.js
new file mode 100644
index 00000000..c00954cd
--- /dev/null
+++ b/frontend/src/models/errors.js
@@ -0,0 +1,34 @@
+import { Record, List } from 'immutable';
+
+const ErrorsRecord = Record({
+ nextId: 0,
+ history: new List(),
+});
+
+export default class ErrorsState extends ErrorsRecord {
+ addError(error) {
+ const errorObject = new Error({ id: this.nextId, error: new ErrorBag(error) });
+ return this.set('history', this.history.push(errorObject)).set('nextId', this.nextId + 1);
+ }
+}
+
+const ErrorRecord = Record({
+ id: -1,
+ timestamp: new Date(),
+ error: new ErrorsRecord(),
+});
+
+export class Error extends ErrorRecord {}
+
+const ErrorBagRecord = Record({
+ type: '',
+ position: 'bottom-left',
+ options: {
+ icon: 'error',
+ removeOnHover: true,
+ showCloseButton: true,
+ },
+ title: 'Unknown Error',
+});
+
+export class ErrorBag extends ErrorBagRecord {}
diff --git a/frontend/src/models/games.js b/frontend/src/models/games.js
new file mode 100644
index 00000000..95bf8015
--- /dev/null
+++ b/frontend/src/models/games.js
@@ -0,0 +1,41 @@
+import { Record, Map, List } from 'immutable';
+
+const SettingsRecord = Record({
+ initialGold: 3,
+ lostPointsPerDefeat: 1,
+ timeLimitInSeconds: 45,
+ randomSeedForTests: -1,
+ discardedCardGold: 3,
+ defaultTradingCost: 2,
+ wonPointsPerVictoryPerAge: {
+ '1': 1,
+ '2': 3,
+ '3': 5,
+ },
+ wonderSidePickMethod: 'EACH_RANDOM',
+ pointsPer3Gold: 1,
+});
+export class Settings extends SettingsRecord {}
+
+const GameRecord = Record({
+ id: -1,
+ name: null,
+ players: new List(),
+ settings: new Settings(),
+ state: 'LOBBY',
+});
+export class Game extends GameRecord {}
+
+const GamesRecord = Record({
+ all: new Map(),
+ current: '',
+});
+export default class GamesState extends GamesRecord {
+ addGame(g) {
+ const game = new Game(g);
+ return this.mergeDeepIn(['all', game.id], game);
+ }
+ addGames(games) {
+ return this.mergeIn(['all'], games.map(game => new Game(game)));
+ }
+}
diff --git a/frontend/src/models/players.js b/frontend/src/models/players.js
new file mode 100644
index 00000000..3df32c57
--- /dev/null
+++ b/frontend/src/models/players.js
@@ -0,0 +1,26 @@
+import { Record, Map } from 'immutable';
+
+const PlayerRecord = Record({
+ username: null,
+ displayName: null,
+ index: 0,
+ ready: false,
+});
+export class Player extends PlayerRecord {}
+
+const PlayersRecord = Record({
+ all: new Map(),
+ current: '',
+});
+export default class PlayerState extends PlayersRecord {
+ addPlayer(p) {
+ const player = new Player(p);
+ const playerMap = new Map({ [player.username]: player });
+ return this.addPlayers(playerMap).set('current', player.username);
+ }
+
+ addPlayers(p) {
+ const players = new Map(p);
+ return this.mergeIn(['all'], players.map(player => new Player(player)));
+ }
+}
diff --git a/frontend/src/reducers.js b/frontend/src/reducers.js
index a7bba09a..4b98a9ca 100644
--- a/frontend/src/reducers.js
+++ b/frontend/src/reducers.js
@@ -1,4 +1,5 @@
-import { combineReducers, routerReducer } from 'redux-seamless-immutable';
+import { combineReducers } from 'redux-immutable';
+import { routerReducer } from 'react-router-redux';
import { reducer as toastrReducer } from 'react-redux-toastr';
import errorsReducer from './redux/errors';
diff --git a/frontend/src/redux/app.js b/frontend/src/redux/app.js
index d24fbbfd..614e7d93 100644
--- a/frontend/src/redux/app.js
+++ b/frontend/src/redux/app.js
@@ -1,5 +1,5 @@
export const makeSelectLocationState = () => {
return state => {
- return state.routing;
+ return state.get('routing');
};
};
diff --git a/frontend/src/redux/errors.js b/frontend/src/redux/errors.js
index ec1e30b6..ad1e2795 100644
--- a/frontend/src/redux/errors.js
+++ b/frontend/src/redux/errors.js
@@ -1,4 +1,4 @@
-import Immutable from 'seamless-immutable';
+import ErrorsState from '../models/errors';
export const types = {
ERROR_RECEIVED_ON_WS: 'ERROR/RECEIVED_ON_WS',
@@ -11,27 +11,11 @@ export const actions = {
}),
};
-const initialState = Immutable.from({
- nextId: 0,
- history: [],
-});
-
-export default (state = initialState, action) => {
+export default (state = new ErrorsState(), action) => {
switch (action.type) {
case types.ERROR_RECEIVED_ON_WS:
- let error = Object.assign({ id: state.nextId, timestamp: new Date() }, action.error);
- let newState = state.set('nextId', state.nextId + 1);
- newState = addErrorToHistory(newState, error);
- return newState;
+ return state.addError(action.error);
default:
return state;
}
};
-
-function addErrorToHistory(state, error) {
- return addToArray(state, 'history', error);
-}
-
-function addToArray(state, arrayKey, element) {
- return state.set(arrayKey, state[arrayKey].concat([element]));
-}
diff --git a/frontend/src/redux/games.js b/frontend/src/redux/games.js
index 9ef0e7cd..d5953db1 100644
--- a/frontend/src/redux/games.js
+++ b/frontend/src/redux/games.js
@@ -1,4 +1,5 @@
-import Immutable from 'seamless-immutable';
+import { fromJS } from 'immutable';
+import GamesState from '../models/games';
export const types = {
UPDATE_GAMES: 'GAME/UPDATE_GAMES',
@@ -10,37 +11,29 @@ export const types = {
};
export const actions = {
- updateGames: games => ({ type: types.UPDATE_GAMES, games: Immutable(games) }),
+ updateGames: games => ({ type: types.UPDATE_GAMES, games: fromJS(games) }),
requestJoinGame: gameId => ({ type: types.REQUEST_JOIN_GAME, gameId }),
requestCreateGame: gameName => ({
type: types.REQUEST_CREATE_GAME,
gameName,
}),
requestStartGame: () => ({ type: types.REQUEST_START_GAME }),
- enterLobby: lobby => ({ type: types.ENTER_LOBBY, lobby: Immutable(lobby) }),
+ enterLobby: lobby => ({ type: types.ENTER_LOBBY, lobby: fromJS(lobby) }),
enterGame: () => ({ type: types.ENTER_GAME }),
};
-const initialState = Immutable.from({
- all: {},
- current: '',
-});
-
-export default (state = initialState, action) => {
+export default (state = new GamesState(), action) => {
switch (action.type) {
case types.UPDATE_GAMES:
- return Immutable.merge(state, { all: action.games }, { deep: true });
+ return state.addGames(action.games);
case types.ENTER_LOBBY:
- return state.set('current', action.lobby.id);
+ return state.set('current', action.lobby.get('id'));
default:
return state;
}
};
-export const getAllGamesById = state => state.games.all;
-export const getAllGames = state => {
- let gamesById = getAllGamesById(state);
- return Object.keys(gamesById).map(k => gamesById[k]);
-};
-export const getGame = (state, id) => getAllGamesById(state)[id];
-export const getCurrentGame = state => getGame(state, state.games.current);
+export const getAllGamesById = games => games.all;
+export const getAllGames = games => getAllGamesById(games).toList();
+export const getGame = (games, id) => getAllGamesById(games).get(`${id}`);
+export const getCurrentGame = games => getGame(games, games.current);
diff --git a/frontend/src/redux/players.js b/frontend/src/redux/players.js
index b11e920f..85b579f3 100644
--- a/frontend/src/redux/players.js
+++ b/frontend/src/redux/players.js
@@ -1,4 +1,4 @@
-import Immutable from 'seamless-immutable';
+import PlayerState, { Player } from '../models/players';
export const types = {
REQUEST_CHOOSE_USERNAME: 'USER/REQUEST_CHOOSE_USERNAME',
@@ -21,24 +21,17 @@ export const actions = {
}),
};
-const initialState = Immutable.from({
- all: {},
- current: '',
-});
-
-export default (state = initialState, action) => {
+export default (state = new PlayerState(), action) => {
switch (action.type) {
case types.SET_CURRENT_PLAYER:
- const player = action.player;
- const withNewPlayer = state.setIn(['all', player.username], player);
- return Immutable.set(withNewPlayer, 'current', player.username);
+ return state.addPlayer(action.player);
case types.UPDATE_PLAYERS:
- return Immutable.merge(state, { all: action.players }, { deep: true });
+ return state.addPlayers(action.players);
default:
return state;
}
};
-export const getCurrentPlayer = state => state.players.all && state.players.all[state.players.current];
-export const getPlayer = (state, username) => state.players.all[username];
-export const getPlayers = (state, usernames) => usernames.map(u => getPlayer(state, u));
+export const getCurrentPlayer = players => players.all.get(players.current, new Player({ displayName: '[ERROR]' }));
+export const getPlayer = (players, username) => players.all.get(username);
+export const getPlayers = (players, usernames) => usernames.map(u => getPlayer(players, u));
diff --git a/frontend/src/store.js b/frontend/src/store.js
index 4bd22184..57f43a4f 100644
--- a/frontend/src/store.js
+++ b/frontend/src/store.js
@@ -1,7 +1,7 @@
import { createStore, applyMiddleware, compose } from 'redux';
import { browserHistory } from 'react-router';
import { syncHistoryWithStore, routerMiddleware } from 'react-router-redux';
-import Immutable from 'seamless-immutable';
+import { fromJS } from 'immutable';
import createReducer from './reducers';
import createSagaMiddleware from 'redux-saga';
@@ -21,7 +21,7 @@ export default function configureStore(initialState = {}) {
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
: compose;
- const store = createStore(createReducer(), Immutable.from(initialState), composeEnhancers(...enhancers));
+ const store = createStore(createReducer(), fromJS(initialState), composeEnhancers(...enhancers));
sagaMiddleware.run(rootSaga, browserHistory);
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 562508ba..902ee743 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -3035,6 +3035,10 @@ ignore@^3.2.0, ignore@^3.2.7:
version "3.3.0"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.0.tgz#3812d22cbe9125f2c2b4915755a1b8abd745a001"
+immutable@^3.8.1:
+ version "3.8.1"
+ resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz#200807f11ab0f72710ea485542de088075f68cd2"
+
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
@@ -5327,6 +5331,10 @@ reduce-function-call@^1.0.1:
dependencies:
balanced-match "^0.4.2"
+redux-immutable@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/redux-immutable/-/redux-immutable-4.0.0.tgz#3a1a32df66366462b63691f0e1dc35e472bbc9f3"
+
redux-saga-router@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/redux-saga-router/-/redux-saga-router-2.1.0.tgz#d049962ad6a44d227f0308aedb75e39c13f58413"
bgstack15