diff options
Diffstat (limited to 'src/main')
28 files changed, 397 insertions, 124 deletions
diff --git a/src/main/java/org/luxons/sevenwonders/actions/StartGameAction.java b/src/main/java/org/luxons/sevenwonders/actions/StartGameAction.java new file mode 100644 index 00000000..632b80ef --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/actions/StartGameAction.java @@ -0,0 +1,19 @@ +package org.luxons.sevenwonders.actions; + +import javax.validation.constraints.NotNull; + +import org.luxons.sevenwonders.game.Settings; + +public class StartGameAction { + + @NotNull + private Settings settings; + + public Settings getSettings() { + return settings; + } + + public void setSettings(Settings settings) { + this.settings = settings; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java b/src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java index 81c90c9b..83629d6a 100644 --- a/src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java +++ b/src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java @@ -24,7 +24,10 @@ public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/seven-wonders-websocket").setHandshakeHandler(handshakeHandler()).withSockJS(); + registry.addEndpoint("/seven-wonders-websocket") + .setHandshakeHandler(handshakeHandler()) + .setAllowedOrigins("http://localhost:3000") // to allow frontend server proxy requests in dev mode + .withSockJS(); } @Bean diff --git a/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java b/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java index ea262c4e..e15935d6 100644 --- a/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java +++ b/src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java @@ -2,13 +2,20 @@ package org.luxons.sevenwonders.controllers; import java.security.Principal; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.luxons.sevenwonders.actions.JoinOrCreateGameAction; +import org.luxons.sevenwonders.actions.StartGameAction; +import org.luxons.sevenwonders.errors.ErrorFactory; +import org.luxons.sevenwonders.errors.UIError; +import org.luxons.sevenwonders.errors.UniqueIdAlreadyUsedException; import org.luxons.sevenwonders.game.Game; import org.luxons.sevenwonders.game.Lobby; import org.luxons.sevenwonders.game.Player; +import org.luxons.sevenwonders.game.api.PlayerTurnInfo; import org.luxons.sevenwonders.game.data.GameDefinitionLoader; +import org.luxons.sevenwonders.session.SessionAttributes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -16,6 +23,7 @@ import org.springframework.messaging.handler.annotation.MessageExceptionHandler; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.simp.SimpMessageHeaderAccessor; +import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.messaging.simp.annotation.SendToUser; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; @@ -26,10 +34,12 @@ public class LobbyController { private static final Logger logger = LoggerFactory.getLogger(LobbyController.class); - public static final String ATTR_LOBBY = "lobby"; - private final GameDefinitionLoader gameDefinitionLoader; + private final SimpMessagingTemplate template; + + private final ErrorFactory errorFactory; + private long lastGameId = 0; private Map<String, Lobby> lobbies = new HashMap<>(); @@ -37,22 +47,25 @@ public class LobbyController { private Map<String, Game> games = new HashMap<>(); @Autowired - public LobbyController(GameDefinitionLoader gameDefinitionLoader) { + public LobbyController(GameDefinitionLoader gameDefinitionLoader, SimpMessagingTemplate template, + ErrorFactory errorFactory) { this.gameDefinitionLoader = gameDefinitionLoader; + this.template = template; + this.errorFactory = errorFactory; } @MessageExceptionHandler @SendToUser("/queue/errors") - public String handleException(Throwable exception) { + public UIError handleException(Throwable exception) { logger.error("An error occured during message handling", exception); - return exception.getClass().getSimpleName() + ": " + exception.getMessage(); + return errorFactory.createError(exception); } @MessageMapping("/create-game") @SendTo("/topic/games") public Lobby createGame(SimpMessageHeaderAccessor headerAccessor, @Validated JoinOrCreateGameAction action, Principal principal) { - Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get(ATTR_LOBBY); + Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get(SessionAttributes.ATTR_LOBBY); if (lobby != null) { logger.warn("Client already in game '{}', cannot create a new game", lobby.getName()); return lobby; @@ -61,7 +74,7 @@ public class LobbyController { Player player = createPlayer(action.getPlayerName(), principal); lobby = createGame(action.getGameName(), player); - headerAccessor.getSessionAttributes().put(ATTR_LOBBY, lobby); + headerAccessor.getSessionAttributes().put(SessionAttributes.ATTR_LOBBY, lobby); logger.info("Game '{}' (id={}) created by {} ({})", lobby.getName(), lobby.getId(), player.getDisplayName(), player.getUserName()); @@ -72,7 +85,7 @@ public class LobbyController { @SendToUser("/queue/join-game") public Lobby joinGame(SimpMessageHeaderAccessor headerAccessor, @Validated JoinOrCreateGameAction action, Principal principal) { - Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get(ATTR_LOBBY); + Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get(SessionAttributes.ATTR_LOBBY); if (lobby != null) { logger.warn("Client already in game '{}', cannot join a different game", lobby.getName()); return lobby; @@ -86,17 +99,42 @@ public class LobbyController { Player newPlayer = createPlayer(action.getPlayerName(), principal); lobby.addPlayer(newPlayer); - headerAccessor.getSessionAttributes().put(ATTR_LOBBY, lobby); + headerAccessor.getSessionAttributes().put(SessionAttributes.ATTR_LOBBY, lobby); logger.warn("Player {} joined game {}", action.getPlayerName(), action.getGameName()); return lobby; } + @MessageMapping("/start-game") + public void startGame(SimpMessageHeaderAccessor headerAccessor, @Validated StartGameAction action, + Principal principal) { + Lobby lobby = (Lobby)headerAccessor.getSessionAttributes().get(SessionAttributes.ATTR_LOBBY); + if (lobby == null) { + logger.error("User {} is not in a lobby", principal.getName()); + template.convertAndSendToUser(principal.getName(), "/queue/errors", "No game to start"); + return; + } + + if (!lobby.isOwner(principal.getName())) { + logger.error("User {} is not the owner of the game '{}'", principal.getName(), lobby.getName()); + template.convertAndSendToUser(principal.getName(), "/queue/errors", "Only the owner can start the game"); + return; + } + + Game game = lobby.startGame(action.getSettings()); + logger.info("Game {} successfully started", game.getId()); + + List<PlayerTurnInfo> playerTurnInfos = game.startTurn(); + for (PlayerTurnInfo playerTurnInfo : playerTurnInfos) { + Player player = playerTurnInfo.getTable().getPlayers().get(playerTurnInfo.getPlayerIndex()); + String userName = player.getUserName(); + template.convertAndSendToUser(userName, "/queue/game/turn", playerTurnInfo); + } + } + private Player createPlayer(String name, Principal principal) { - Player player = new Player(name); - player.setUserName(principal.getName()); - return player; + return new Player(name, principal.getName()); } private Lobby createGame(String name, Player owner) { @@ -114,7 +152,6 @@ public class LobbyController { public GameNotFoundException(String name) { super(name); } - } private class GameNameAlreadyUsedException extends UniqueIdAlreadyUsedException { @@ -123,5 +160,4 @@ public class LobbyController { super(name); } } - } diff --git a/src/main/java/org/luxons/sevenwonders/errors/ErrorFactory.java b/src/main/java/org/luxons/sevenwonders/errors/ErrorFactory.java new file mode 100644 index 00000000..2d3dcd0b --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/errors/ErrorFactory.java @@ -0,0 +1,52 @@ +package org.luxons.sevenwonders.errors; + +import java.util.List; +import java.util.Locale; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException; +import org.springframework.stereotype.Component; +import org.springframework.validation.ObjectError; + +@Component +public class ErrorFactory { + + private static final String ERROR_CODE_VALIDATION = "VALIDATION_ERROR"; + + private static final String ERROR_MSG_VALIDATION = "Input invalid"; + + private final MessageSource messageSource; + + @Autowired + public ErrorFactory(MessageSource messageSource) { + this.messageSource = messageSource; + } + + public UIError createError(Throwable exception) { + if (exception instanceof UserInputException) { + return createUserError((UserInputException)exception); + } else if (exception instanceof MethodArgumentNotValidException) { + return createValidationError((MethodArgumentNotValidException)exception); + } else { + return createInternalError(exception); + } + } + + private UIError createUserError(UserInputException exception) { + String messageKey = exception.getMessageResourceKey(); + String message = messageSource.getMessage(messageKey, null, messageKey, Locale.US); + return new UIError(messageKey, message, ErrorType.USER); + } + + private UIError createInternalError(Throwable exception) { + return new UIError(exception.getClass().getSimpleName(), exception.getMessage(), ErrorType.INTERNAL); + } + + private UIError createValidationError(MethodArgumentNotValidException exception) { + List<ObjectError> errors = exception.getBindingResult().getAllErrors(); + UIError uiError = new UIError(ERROR_CODE_VALIDATION, ERROR_MSG_VALIDATION, ErrorType.VALIDATION); + uiError.setValidationErrors(errors); + return uiError; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/errors/ErrorType.java b/src/main/java/org/luxons/sevenwonders/errors/ErrorType.java new file mode 100644 index 00000000..71df185f --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/errors/ErrorType.java @@ -0,0 +1,7 @@ +package org.luxons.sevenwonders.errors; + +public enum ErrorType { + USER, + VALIDATION, + INTERNAL +} diff --git a/src/main/java/org/luxons/sevenwonders/errors/UIError.java b/src/main/java/org/luxons/sevenwonders/errors/UIError.java new file mode 100644 index 00000000..67802f22 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/errors/UIError.java @@ -0,0 +1,42 @@ +package org.luxons.sevenwonders.errors; + +import java.util.List; + +import org.springframework.validation.ObjectError; + +public class UIError { + + private final String code; + + private final String message; + + private final ErrorType type; + + private List<ObjectError> validationErrors; + + public UIError(String code, String message, ErrorType type) { + this.code = code; + this.message = message; + this.type = type; + } + + public String getCode() { + return code; + } + + public String getMessage() { + return message; + } + + public ErrorType getType() { + return type; + } + + public List<ObjectError> getValidationErrors() { + return validationErrors; + } + + public void setValidationErrors(List<ObjectError> validationErrors) { + this.validationErrors = validationErrors; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/controllers/UniqueIdAlreadyUsedException.java b/src/main/java/org/luxons/sevenwonders/errors/UniqueIdAlreadyUsedException.java index 56c22655..b1b00453 100644 --- a/src/main/java/org/luxons/sevenwonders/controllers/UniqueIdAlreadyUsedException.java +++ b/src/main/java/org/luxons/sevenwonders/errors/UniqueIdAlreadyUsedException.java @@ -1,4 +1,4 @@ -package org.luxons.sevenwonders.controllers; +package org.luxons.sevenwonders.errors; public class UniqueIdAlreadyUsedException extends RuntimeException { diff --git a/src/main/java/org/luxons/sevenwonders/errors/UserInputException.java b/src/main/java/org/luxons/sevenwonders/errors/UserInputException.java new file mode 100644 index 00000000..11f7f8f2 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/errors/UserInputException.java @@ -0,0 +1,14 @@ +package org.luxons.sevenwonders.errors; + +public class UserInputException extends RuntimeException { + + private final String messageResourceKey; + + public UserInputException(String messageResourceKey) { + this.messageResourceKey = messageResourceKey; + } + + public String getMessageResourceKey() { + return messageResourceKey; + } +} diff --git a/src/main/java/org/luxons/sevenwonders/game/Game.java b/src/main/java/org/luxons/sevenwonders/game/Game.java index f4dac7ef..2a2fab27 100644 --- a/src/main/java/org/luxons/sevenwonders/game/Game.java +++ b/src/main/java/org/luxons/sevenwonders/game/Game.java @@ -37,22 +37,23 @@ public class Game { this.discardedCards = new ArrayList<>(); this.hands = new HashMap<>(); this.preparedMoves = new HashMap<>(); + startNewAge(); } public long getId() { return id; } - public int startNewAge() { + private void startNewAge() { currentAge++; hands = decks.deal(currentAge, table.getNbPlayers()); - return currentAge; } public List<PlayerTurnInfo> startTurn() { return hands.entrySet() .stream() .map(e -> table.createPlayerTurnInfo(e.getKey(), e.getValue())) + .peek(ptu -> ptu.setCurrentAge(currentAge)) .collect(Collectors.toList()); } @@ -69,10 +70,27 @@ public class Game { return preparedMoves.size() == table.getPlayers().size(); } - public void playTurn() { + public List<Move> playTurn() { + List<Move> playedMoves = mapToList(preparedMoves); + // cards need to be all placed first as some effects depend on just-played cards placePreparedCards(); playPreparedCards(); + preparedMoves.clear(); + + return playedMoves; + } + + private static List<Move> mapToList(Map<Integer, Move> movesPerPlayer) { + List<Move> moves = new ArrayList<>(movesPerPlayer.size()); + for (int p = 0; p < movesPerPlayer.size(); p++) { + Move move = movesPerPlayer.get(p); + if (move == null) { + throw new MissingPreparedMoveException(p); + } + moves.add(move); + } + return moves; } private void placePreparedCards() { @@ -85,10 +103,10 @@ public class Game { // TODO pre-upgrade the level of wonder without effect break; case DISCARD: + discardedCards.add(decks.getCard(move.getCardName())); break; } }); - } private void playPreparedCards() { @@ -108,6 +126,13 @@ public class Game { } - public class InvalidMoveException extends RuntimeException { + private static class MissingPreparedMoveException extends RuntimeException { + + public MissingPreparedMoveException(int playerIndex) { + super("Player " + playerIndex + " is not ready to play"); + } + } + + private static class InvalidMoveException extends RuntimeException { } } diff --git a/src/main/java/org/luxons/sevenwonders/game/Lobby.java b/src/main/java/org/luxons/sevenwonders/game/Lobby.java index 7256936c..16d4e8a3 100644 --- a/src/main/java/org/luxons/sevenwonders/game/Lobby.java +++ b/src/main/java/org/luxons/sevenwonders/game/Lobby.java @@ -3,7 +3,7 @@ package org.luxons.sevenwonders.game; import java.util.ArrayList; import java.util.List; -import org.luxons.sevenwonders.controllers.UniqueIdAlreadyUsedException; +import org.luxons.sevenwonders.errors.UniqueIdAlreadyUsedException; import org.luxons.sevenwonders.game.data.GameDefinition; public class Lobby { @@ -12,6 +12,8 @@ public class Lobby { private final String name; + private final Player owner; + private final List<Player> players; private final GameDefinition gameDefinition; @@ -21,6 +23,7 @@ public class Lobby { public Lobby(long id, String name, Player owner, GameDefinition gameDefinition) { this.id = id; this.name = name; + this.owner = owner; this.gameDefinition = gameDefinition; this.players = new ArrayList<>(gameDefinition.getMinPlayers()); players.add(owner); @@ -79,6 +82,10 @@ public class Lobby { return "Lobby{" + "id=" + id + ", name='" + name + '\'' + ", state=" + state + '}'; } + public boolean isOwner(String userName) { + return owner.getUserName().equals(userName); + } + public class GameAlreadyStartedException extends IllegalStateException { } diff --git a/src/main/java/org/luxons/sevenwonders/game/Player.java b/src/main/java/org/luxons/sevenwonders/game/Player.java index fd2f254b..66ce566d 100644 --- a/src/main/java/org/luxons/sevenwonders/game/Player.java +++ b/src/main/java/org/luxons/sevenwonders/game/Player.java @@ -2,30 +2,23 @@ package org.luxons.sevenwonders.game; public class Player { - private String displayName; + private final String displayName; - private String userName; + private final String userName; - public Player(String displayName) { + public Player(String displayName, String userName) { this.displayName = displayName; + this.userName = userName; } public String getDisplayName() { return displayName; } - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - public String getUserName() { return userName; } - public void setUserName(String userName) { - this.userName = userName; - } - @Override public String toString() { return "Player{" + "name='" + displayName + '\'' + ", userName='" + userName + '\'' + '}'; diff --git a/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java b/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java index ad9e6da9..b7090ff9 100644 --- a/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java +++ b/src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java @@ -8,6 +8,8 @@ public class PlayerTurnInfo { private final Table table; + private int currentAge; + private List<HandCard> hand; private String message; @@ -25,6 +27,14 @@ public class PlayerTurnInfo { return table; } + public int getCurrentAge() { + return currentAge; + } + + public void setCurrentAge(int currentAge) { + this.currentAge = currentAge; + } + public List<HandCard> getHand() { return hand; } diff --git a/src/main/java/org/luxons/sevenwonders/session/SessionAttributes.java b/src/main/java/org/luxons/sevenwonders/session/SessionAttributes.java new file mode 100644 index 00000000..8c69d8c3 --- /dev/null +++ b/src/main/java/org/luxons/sevenwonders/session/SessionAttributes.java @@ -0,0 +1,8 @@ +package org.luxons.sevenwonders.session; + +public class SessionAttributes { + + public static final String ATTR_LOBBY = "lobby"; + + public static final String ATTR_GAME = "game"; +} diff --git a/src/main/js/.editorconfig b/src/main/js/.editorconfig new file mode 100644 index 00000000..32c3b3d4 --- /dev/null +++ b/src/main/js/.editorconfig @@ -0,0 +1,9 @@ +root = false + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 2
\ No newline at end of file diff --git a/src/main/js/package.json b/src/main/js/package.json index 0c1bdbb9..b3ad0282 100644 --- a/src/main/js/package.json +++ b/src/main/js/package.json @@ -11,10 +11,13 @@ "react-dom": "^15.4.1", "react-redux": "^5.0.1", "react-router": "4.0.0-alpha.6", + "rebass": "^0.3.3", + "reflexbox": "^2.2.3", "redux": "^3.6.0", "redux-saga": "^0.13.0", "sockjs-client": "latest", - "webstomp-client": "^1.0.3" + "webstomp-client": "^1.0.3", + "redux-saga": "^0.13.0" }, "scripts": { "start": "react-scripts start", diff --git a/src/main/js/src/components/.gitkeep b/src/main/js/src/components/.gitkeep deleted file mode 100644 index e69de29b..00000000 --- a/src/main/js/src/components/.gitkeep +++ /dev/null diff --git a/src/main/js/src/components/errors/Error404.js b/src/main/js/src/components/errors/Error404.js index 13ce5ae5..b657482d 100644 --- a/src/main/js/src/components/errors/Error404.js +++ b/src/main/js/src/components/errors/Error404.js @@ -1,8 +1,8 @@ import React from 'react' import { Link } from 'react-router' -const Error404 = () => <div> - <h1>No Match</h1> - <Link to="/">Take me back home ! 🏠</Link> +const Error404 = () => <div> + <h1>No Match</h1> + <Link to="/">Take me back home ! 🏠</Link> </div> export default Error404
\ No newline at end of file diff --git a/src/main/js/src/containers/.gitkeep b/src/main/js/src/containers/.gitkeep deleted file mode 100644 index e69de29b..00000000 --- a/src/main/js/src/containers/.gitkeep +++ /dev/null diff --git a/src/main/js/src/containers/Counter/actions.js b/src/main/js/src/containers/Counter/actions.js index 01cd8d67..abd6babb 100644 --- a/src/main/js/src/containers/Counter/actions.js +++ b/src/main/js/src/containers/Counter/actions.js @@ -1,20 +1,20 @@ import { - INCREMENT, DECREMENT, - INCREMENT_IF_ODD, INCREMENT_ASYNC + INCREMENT, DECREMENT, + INCREMENT_IF_ODD, INCREMENT_ASYNC } from './constants' export const increment = () => ({ - type: INCREMENT + type: INCREMENT }) export const decrement = () => ({ - type: DECREMENT + type: DECREMENT }) export const incrementIfOdd = () => ({ - type: INCREMENT_IF_ODD + type: INCREMENT_IF_ODD }) export const incrementAsync = () => ({ - type: INCREMENT_ASYNC + type: INCREMENT_ASYNC })
\ No newline at end of file diff --git a/src/main/js/src/containers/Counter/index.js b/src/main/js/src/containers/Counter/index.js index a91af8f5..0be665fd 100644 --- a/src/main/js/src/containers/Counter/index.js +++ b/src/main/js/src/containers/Counter/index.js @@ -2,50 +2,50 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' import { - increment, - decrement, - incrementAsync, - incrementIfOdd + increment, + decrement, + incrementAsync, + incrementIfOdd } from './actions' -const Counter = ({ value, increment, decrement, incrementIfOdd, incrementAsync }) => - <p> - Clicked: {value} times - {' '} - <button onClick={increment}> - + - </button> - {' '} - <button onClick={decrement}> - - - </button> - {' '} - <button onClick={incrementIfOdd}> - Increment if odd - </button> - {' '} - <button onClick={incrementAsync}> - Increment async - </button> - </p> +const Counter = ({value, increment, decrement, incrementIfOdd, incrementAsync}) => + <p> + Clicked: {value} times + {' '} + <button onClick={increment}> + + + </button> + {' '} + <button onClick={decrement}> + - + </button> + {' '} + <button onClick={incrementIfOdd}> + Increment if odd + </button> + {' '} + <button onClick={incrementAsync}> + Increment async + </button> + </p> Counter.propTypes = { - value: PropTypes.number.isRequired, - increment: PropTypes.func.isRequired, - decrement: PropTypes.func.isRequired, - incrementAsync: PropTypes.func.isRequired, - incrementIfOdd: PropTypes.func.isRequired + value: PropTypes.number.isRequired, + increment: PropTypes.func.isRequired, + decrement: PropTypes.func.isRequired, + incrementAsync: PropTypes.func.isRequired, + incrementIfOdd: PropTypes.func.isRequired } const mapStateToProps = (state) => ({ - value: state.counter + value: state.counter }) const mapDispatchToProps = { - increment, - decrement, - incrementAsync, - incrementIfOdd + increment, + decrement, + incrementAsync, + incrementIfOdd } export default connect(mapStateToProps, mapDispatchToProps)(Counter)
\ No newline at end of file diff --git a/src/main/js/src/containers/Counter/reducer.js b/src/main/js/src/containers/Counter/reducer.js index 586c4e0a..44006f3e 100644 --- a/src/main/js/src/containers/Counter/reducer.js +++ b/src/main/js/src/containers/Counter/reducer.js @@ -1,17 +1,17 @@ import { - INCREMENT, DECREMENT, - INCREMENT_IF_ODD + INCREMENT, DECREMENT, + INCREMENT_IF_ODD } from './constants' export default function reducer(state = 0, action) { - switch (action.type) { - case INCREMENT: - return state + 1 - case DECREMENT: - return state - 1 - case INCREMENT_IF_ODD: - return (state % 2 === 0) ? state + 1 : state - default: - return state - } + switch (action.type) { + case INCREMENT: + return state + 1 + case DECREMENT: + return state - 1 + case INCREMENT_IF_ODD: + return (state % 2 === 0) ? state + 1 : state + default: + return state + } }
\ No newline at end of file diff --git a/src/main/js/src/containers/Counter/saga.js b/src/main/js/src/containers/Counter/saga.js index fe210620..0b9e2866 100644 --- a/src/main/js/src/containers/Counter/saga.js +++ b/src/main/js/src/containers/Counter/saga.js @@ -5,10 +5,10 @@ import { increment } from './actions' import { INCREMENT_ASYNC } from './constants' export function* incrementAsync() { - yield call(delay, 1000) - yield put(increment()) + yield call(delay, 1000) + yield put(increment()) } export default function* counterSaga() { - yield takeEvery(INCREMENT_ASYNC, incrementAsync) + yield takeEvery(INCREMENT_ASYNC, incrementAsync) }
\ No newline at end of file diff --git a/src/main/js/src/global-styles.css b/src/main/js/src/global-styles.css index b4cc7250..4b644b66 100644 --- a/src/main/js/src/global-styles.css +++ b/src/main/js/src/global-styles.css @@ -1,5 +1,10 @@ +* { box-sizing: border-box; } + body { margin: 0; padding: 0; - font-family: sans-serif; -} + font-family: -apple-system, BlinkMacSystemFont, sans-serif; + line-height: 1.5; + color: #111; + background-color: #fff; +}
\ No newline at end of file diff --git a/src/main/js/src/index.js b/src/main/js/src/index.js index 926c756a..97af0f59 100644 --- a/src/main/js/src/index.js +++ b/src/main/js/src/index.js @@ -16,13 +16,13 @@ import Error404 from './components/errors/Error404' ReactDOM.render( <Provider store={store}> - <BrowserRouter> - <div className="app"> - <Match exactly pattern="/" component={App} /> - <Match exactly pattern="/counter" component={Counter}/> - <Miss component={Error404} /> - </div> - </BrowserRouter> + <BrowserRouter> + <div className="app"> + <Match exactly pattern="/" component={App}/> + <Match exactly pattern="/counter" component={Counter}/> + <Miss component={Error404}/> + </div> + </BrowserRouter> </Provider>, document.getElementById('root') ); diff --git a/src/main/js/src/reducers.js b/src/main/js/src/reducers.js index 82540b00..79014615 100644 --- a/src/main/js/src/reducers.js +++ b/src/main/js/src/reducers.js @@ -2,7 +2,7 @@ import { combineReducers } from 'redux' import counterReducer from './containers/Counter/reducer' export default function createReducer() { - return combineReducers({ - counter: counterReducer - }) + return combineReducers({ + counter: counterReducer + }) }
\ No newline at end of file diff --git a/src/main/js/src/store.js b/src/main/js/src/store.js index bbeb51bd..31c8aa71 100644 --- a/src/main/js/src/store.js +++ b/src/main/js/src/store.js @@ -5,29 +5,29 @@ import createSagaMiddleware from 'redux-saga' import rootSaga from './sagas' export default function configureStore(initialState = {}) { - const sagaMiddleware = createSagaMiddleware() + const sagaMiddleware = createSagaMiddleware() - const middlewares = [ - sagaMiddleware - ] + const middlewares = [ + sagaMiddleware + ] - const enhancers = [ - applyMiddleware(...middlewares) - ] + const enhancers = [ + applyMiddleware(...middlewares) + ] - const composeEnhancers = - process.env.NODE_ENV !== 'production' && - typeof window === 'object' && - window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? - window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose; + const composeEnhancers = + process.env.NODE_ENV !== 'production' && + typeof window === 'object' && + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose; - const store = createStore( - createReducer(), - initialState, - composeEnhancers(...enhancers) - ) + const store = createStore( + createReducer(), + initialState, + composeEnhancers(...enhancers) + ) - sagaMiddleware.run(rootSaga) + sagaMiddleware.run(rootSaga) - return store + return store } diff --git a/src/main/js/yarn.lock b/src/main/js/yarn.lock index bd375f1c..5eeb79b4 100644 --- a/src/main/js/yarn.lock +++ b/src/main/js/yarn.lock @@ -1142,6 +1142,10 @@ clap@^1.0.9: dependencies: chalk "^1.1.3" +classnames@^2.2.3: + version "2.2.5" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" + clean-css@3.4.x: version "3.4.21" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.21.tgz#2101d5dbd19d63dbc16a75ebd570e7c33948f65b" @@ -4193,6 +4197,10 @@ rc@~1.1.6: minimist "^1.2.0" strip-json-comments "~1.0.4" +react-addons-pure-render-mixin@^15.3.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/react-addons-pure-render-mixin/-/react-addons-pure-render-mixin-15.4.1.tgz#8a1f48f9fd3f24ed12af63c4d2dc0c7529fa7e02" + react-broadcast@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/react-broadcast/-/react-broadcast-0.1.2.tgz#950de63578a2af399a396067a617af7402182330" @@ -4360,6 +4368,14 @@ readline2@^1.0.1: is-fullwidth-code-point "^1.0.0" mute-stream "0.0.5" +rebass: + version "0.3.3" + resolved "https://registry.yarnpkg.com/rebass/-/rebass-0.3.3.tgz#bfffddf219107b07be2133173bab9b9887098173" + dependencies: + classnames "^2.2.3" + object-assign "^4.0.1" + react-addons-pure-render-mixin "^15.3.1" + recursive-readdir@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.1.0.tgz#78b7bfd79582d3d7596b8ff1bd29fbd50229f6aa" @@ -4399,6 +4415,13 @@ redux-saga: version "0.13.0" resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-0.13.0.tgz#9294386550deb0d56bc9a1b3c90a613e7ddb6593" +reflexbox: + version "2.2.3" + resolved "https://registry.yarnpkg.com/reflexbox/-/reflexbox-2.2.3.tgz#9b9ce983dbe677cebf3a94cf2c50b8157f50c0d1" + dependencies: + robox "^1.0.0-beta.8" + ruled "^1.0.1" + regenerate@^1.2.1: version "1.3.2" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" @@ -4555,6 +4578,16 @@ ripemd160@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce" +robox@^1.0.0-beta.8: + version "1.0.0-beta.8" + resolved "https://registry.yarnpkg.com/robox/-/robox-1.0.0-beta.8.tgz#9aaee1dacf38a8c4ca4584a80012aebab5711c73" + dependencies: + understyle "^1.2.0" + +ruled@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ruled/-/ruled-1.0.1.tgz#8301a1accc9d2e14b6502fca7033582335c2c0f4" + run-async@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" @@ -5027,6 +5060,12 @@ uid-number@~0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" +understyle@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/understyle/-/understyle-1.3.0.tgz#df3f9a9be96779d718c3da9598fad1c2f90f24ee" + dependencies: + object-assign "^4.1.0" + uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" diff --git a/src/main/resources/static/app.js b/src/main/resources/static/app.js index b1881357..ace23fdb 100644 --- a/src/main/resources/static/app.js +++ b/src/main/resources/static/app.js @@ -19,7 +19,8 @@ function connect() { console.log('Connected: ' + frame); stompClient.subscribe('/user/queue/errors', function (msg) { - console.error(msg.body); + var error = JSON.parse(msg.body); + console.error(error); }); stompClient.subscribe('/topic/games', function (msg) { |