diff options
-rw-r--r-- | frontend/package.json | 2 | ||||
-rw-r--r-- | frontend/public/index.html | 1 | ||||
-rw-r--r-- | frontend/src/components/errors/errorToast | 9 | ||||
-rw-r--r-- | frontend/src/components/gameList.js | 1 | ||||
-rw-r--r-- | frontend/src/layouts/HomeLayout.js | 10 | ||||
-rw-r--r-- | frontend/src/layouts/LobbyLayout.js | 10 | ||||
-rw-r--r-- | frontend/src/reducers.js | 2 | ||||
-rw-r--r-- | frontend/src/redux/errors.js | 20 | ||||
-rw-r--r-- | frontend/src/sagas/errors.js | 20 | ||||
-rw-r--r-- | frontend/src/sagas/gameBrowser.js | 16 | ||||
-rw-r--r-- | frontend/src/sagas/home.js | 17 | ||||
-rw-r--r-- | frontend/yarn.lock | 40 |
12 files changed, 94 insertions, 54 deletions
diff --git a/frontend/package.json b/frontend/package.json index 49fe9cc6..6c129927 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,9 +11,9 @@ "react": "latest", "react-dom": "latest", "react-redux": "latest", + "react-redux-toastr": "latest", "react-router": "^3.0.2", "react-router-redux": "latest", - "react-toastify": "latest", "rebass": "latest", "redux": "latest", "redux-saga": "latest", diff --git a/frontend/public/index.html b/frontend/public/index.html index aab5e3b0..6a375403 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -4,6 +4,7 @@ <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> + <link href="http://diegoddox.github.io/react-redux-toastr/5.0/react-redux-toastr.min.css" rel="stylesheet" type="text/css"> <!-- Notice the use of %PUBLIC_URL% in the tag above. It will be replaced with the URL of the `public` folder during the build. diff --git a/frontend/src/components/errors/errorToast b/frontend/src/components/errors/errorToast new file mode 100644 index 00000000..39020088 --- /dev/null +++ b/frontend/src/components/errors/errorToast @@ -0,0 +1,9 @@ +import React from 'react' + +const MyToastContent = (props) => ( + <div> + <span>{props.myContent.message}</span> + </div> +) + +export default MyToastContent diff --git a/frontend/src/components/gameList.js b/frontend/src/components/gameList.js index f49a7589..b4167927 100644 --- a/frontend/src/components/gameList.js +++ b/frontend/src/components/gameList.js @@ -6,7 +6,6 @@ import Immutable from 'seamless-immutable' const GameList = (props) => ( <div> {Immutable.asMutable(props.games).map((game, index) => { - const joinGame = () => props.joinGame(game.id) return (<Flex key={index}> diff --git a/frontend/src/layouts/HomeLayout.js b/frontend/src/layouts/HomeLayout.js index 4b93a163..76236383 100644 --- a/frontend/src/layouts/HomeLayout.js +++ b/frontend/src/layouts/HomeLayout.js @@ -1,9 +1,8 @@ import React from 'react' -import { - Banner -} from 'rebass' +import { Banner } from 'rebass' import logo from './logo-7-wonders.png' import background from './background-zeus-temple.jpg' +import ReduxToastr from 'react-redux-toastr' export default (props) => ( <div> @@ -11,5 +10,10 @@ export default (props) => ( <img src={logo} alt="Seven Wonders"/> {props.children} </Banner> + <ReduxToastr + timeOut={4000} + preventDuplicates + position="bottom-left" + progressBar/> </div> ) diff --git a/frontend/src/layouts/LobbyLayout.js b/frontend/src/layouts/LobbyLayout.js index 83c210a1..dba3d589 100644 --- a/frontend/src/layouts/LobbyLayout.js +++ b/frontend/src/layouts/LobbyLayout.js @@ -1,8 +1,7 @@ import React from 'react' -import { - Banner, -} from 'rebass' +import { Banner } from 'rebass' import logo from './logo-7-wonders.png' +import ReduxToastr from 'react-redux-toastr' export default (props) => ( <div> @@ -14,5 +13,10 @@ export default (props) => ( <img src={logo} alt="Seven Wonders Logo"/> </Banner> {props.children} + <ReduxToastr + timeOut={4000} + preventDuplicates + position="bottom-left" + progressBar/> </div> ) diff --git a/frontend/src/reducers.js b/frontend/src/reducers.js index 7e5fba26..f5063ac1 100644 --- a/frontend/src/reducers.js +++ b/frontend/src/reducers.js @@ -1,4 +1,5 @@ import { combineReducers, routerReducer } from 'redux-seamless-immutable' +import { reducer as toastrReducer } from 'react-redux-toastr' import errorsReducer from './redux/errors' import gamesReducer from './redux/games' @@ -10,5 +11,6 @@ export default function createReducer() { games: gamesReducer, players: playersReducer, routing: routerReducer, + toastr: toastrReducer }) } diff --git a/frontend/src/redux/errors.js b/frontend/src/redux/errors.js index 1c247955..7d113db1 100644 --- a/frontend/src/redux/errors.js +++ b/frontend/src/redux/errors.js @@ -8,16 +8,30 @@ export const actions = { errorReceived: (error) => ({ type: types.ERROR_RECEIVED_ON_WS, error - }) + }), } -const initialState = Immutable.from([]) +const initialState = Immutable.from({ + nextId: 0, + history: [] +}) export default (state = initialState, action) => { switch (action.type) { case types.ERROR_RECEIVED_ON_WS: - return state.concat([ action.error ]) + 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 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/sagas/errors.js b/frontend/src/sagas/errors.js index 441f3fb5..9808fe41 100644 --- a/frontend/src/sagas/errors.js +++ b/frontend/src/sagas/errors.js @@ -1,8 +1,11 @@ +import React from 'react' import { apply, call, cancelled, put, take } from 'redux-saga/effects' import { createSubscriptionChannel } from '../utils/websocket' import { actions } from '../redux/errors' +import {toastr} from 'react-redux-toastr' + export default function *errorHandlingSaga({ socket }) { const errorChannel = yield call(createSubscriptionChannel, socket, '/user/queue/errors') try { @@ -12,12 +15,23 @@ export default function *errorHandlingSaga({ socket }) { } } finally { if (yield cancelled()) { + console.log('Error management saga cancelled') yield apply(errorChannel, errorChannel.close) } } } -function *handleOneError(error) { - console.error("Error received on web socket channel", error) - yield put(actions.errorReceived(error)) +function *handleOneError(err) { + console.error("Error received on web socket channel", err) + const msg = buildMsg(err) + yield apply(toastr, toastr.error, [msg, {icon: 'error'}]) + yield put(actions.errorReceived(err)) +} + +function buildMsg(err) { + if (err.details.length > 0) { + return err.details.map(d => d.message).join('\n') + } else { + return err.message + } } diff --git a/frontend/src/sagas/gameBrowser.js b/frontend/src/sagas/gameBrowser.js index 10d6ec1d..b12587ef 100644 --- a/frontend/src/sagas/gameBrowser.js +++ b/frontend/src/sagas/gameBrowser.js @@ -3,7 +3,7 @@ import { createSubscriptionChannel } from '../utils/websocket' import { push } from 'react-router-redux' import { normalize } from 'normalizr' -import { game as gameSchema, gameList as gameListSchema} from '../schemas/games' +import { game as gameSchema, gameList as gameListSchema } from '../schemas/games' import { actions as gameActions, types } from '../redux/games' import { actions as playerActions } from '../redux/players' @@ -39,15 +39,17 @@ function *watchLobbyJoined({socket}) { } function *createGame({socket}) { - const {gameName} = yield take(types.REQUEST_CREATE_GAME) - - yield apply(socket, socket.send, ['/app/lobby/create', JSON.stringify({gameName}), {}]) + while (true) { + const {gameName} = yield take(types.REQUEST_CREATE_GAME) + yield apply(socket, socket.send, ['/app/lobby/create', JSON.stringify({gameName}), {}]) + } } function *joinGame({socket}) { - const {gameId} = yield take(types.REQUEST_JOIN_GAME) - - yield apply(socket, socket.send, ['/app/lobby/join', JSON.stringify({gameId}), {}]) + while (true) { + const {gameId} = yield take(types.REQUEST_JOIN_GAME) + yield apply(socket, socket.send, ['/app/lobby/join', JSON.stringify({gameId}), {}]) + } } function *gameBrowserSaga(socketConnection) { diff --git a/frontend/src/sagas/home.js b/frontend/src/sagas/home.js index 99e6f954..151fcb57 100644 --- a/frontend/src/sagas/home.js +++ b/frontend/src/sagas/home.js @@ -5,17 +5,20 @@ import { push } from 'react-router-redux' import { actions, types } from '../redux/players' function *sendUsername({ socket }) { - const {username} = yield take(types.REQUEST_CHOOSE_USERNAME) - - yield apply(socket, socket.send, ['/app/chooseName', JSON.stringify({ playerName: username })]) + while (true) { + const {username} = yield take(types.REQUEST_CHOOSE_USERNAME) + yield apply(socket, socket.send, ['/app/chooseName', JSON.stringify({playerName: username})]) + } } function *validateUsername({ socket }) { const usernameChannel = yield call(createSubscriptionChannel, socket, '/user/queue/nameChoice') - const user = yield take(usernameChannel) - yield put(actions.setCurrentPlayer(user)) - yield apply(usernameChannel, usernameChannel.close) - yield put(push('/games')) + while (true) { + const user = yield take(usernameChannel) + yield put(actions.setCurrentPlayer(user)) + yield apply(usernameChannel, usernameChannel.close) + yield put(push('/games')) + } } function *usernameChoiceSaga(wsConnection) { diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 545eb202..fd465aac 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1065,10 +1065,6 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chain-function@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc" - chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -1591,10 +1587,6 @@ dom-converter@~0.1: dependencies: utila "~0.3" -dom-helpers@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a" - dom-serializer@0: version "0.1.0" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" @@ -1939,6 +1931,10 @@ eventemitter3@1.x.x: version "1.2.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" +eventemitter3@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba" + events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -2379,7 +2375,7 @@ history@^3.0.0: query-string "^4.2.2" warning "^3.0.0" -history@^4.3.0, history@latest: +history@^4.3.0: version "4.6.1" resolved "https://registry.yarnpkg.com/history/-/history-4.6.1.tgz#911cf8eb65728555a94f2b12780a0c531a14d2fd" dependencies: @@ -4092,7 +4088,7 @@ promise@7.1.1, promise@^7.1.1: dependencies: asap "~2.0.3" -prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@~15.5.7: +prop-types@^15.5.6, prop-types@^15.5.7, prop-types@~15.5.7: version "15.5.10" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154" dependencies: @@ -4211,6 +4207,14 @@ react-redux: lodash-es "^4.2.0" loose-envify "^1.1.0" +react-redux-toastr@latest: + version "6.2.6" + resolved "https://registry.yarnpkg.com/react-redux-toastr/-/react-redux-toastr-6.2.6.tgz#d02166bb9f172fa383bc9d59cf6c25308fe5735b" + dependencies: + classnames "^2.2.3" + eventemitter3 "^2.0.3" + prop-types "^15.5.7" + react-router-redux@^4.0.0, react-router-redux@latest: version "4.0.8" resolved "https://registry.yarnpkg.com/react-router-redux/-/react-router-redux-4.0.8.tgz#227403596b5151e182377dab835b5d45f0f8054e" @@ -4272,22 +4276,6 @@ react-scripts@latest: optionalDependencies: fsevents "1.0.17" -react-toastify@latest: - version "1.5.0" - resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-1.5.0.tgz#e9857e0b5d640064e5ba6caf7a96bb1578273de7" - dependencies: - prop-types "^15.5.8" - react-transition-group "^1.1.2" - -react-transition-group@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.1.3.tgz#5e02cf6e44a863314ff3c68a0c826c2d9d70b221" - dependencies: - chain-function "^1.0.0" - dom-helpers "^3.2.0" - prop-types "^15.5.6" - warning "^3.0.0" - react@latest: version "15.5.4" resolved "https://registry.yarnpkg.com/react/-/react-15.5.4.tgz#fa83eb01506ab237cdc1c8c3b1cea8de012bf047" |