summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.gradle2
-rw-r--r--src/main/java/org/luxons/sevenwonders/actions/StartGameAction.java19
-rw-r--r--src/main/java/org/luxons/sevenwonders/config/WebSocketConfig.java5
-rw-r--r--src/main/java/org/luxons/sevenwonders/controllers/LobbyController.java64
-rw-r--r--src/main/java/org/luxons/sevenwonders/errors/ErrorFactory.java52
-rw-r--r--src/main/java/org/luxons/sevenwonders/errors/ErrorType.java7
-rw-r--r--src/main/java/org/luxons/sevenwonders/errors/UIError.java42
-rw-r--r--src/main/java/org/luxons/sevenwonders/errors/UniqueIdAlreadyUsedException.java (renamed from src/main/java/org/luxons/sevenwonders/controllers/UniqueIdAlreadyUsedException.java)2
-rw-r--r--src/main/java/org/luxons/sevenwonders/errors/UserInputException.java14
-rw-r--r--src/main/java/org/luxons/sevenwonders/game/Game.java35
-rw-r--r--src/main/java/org/luxons/sevenwonders/game/Lobby.java9
-rw-r--r--src/main/java/org/luxons/sevenwonders/game/Player.java15
-rw-r--r--src/main/java/org/luxons/sevenwonders/game/api/PlayerTurnInfo.java10
-rw-r--r--src/main/java/org/luxons/sevenwonders/session/SessionAttributes.java8
-rw-r--r--src/main/js/.editorconfig9
-rw-r--r--src/main/js/package.json5
-rw-r--r--src/main/js/src/components/.gitkeep0
-rw-r--r--src/main/js/src/components/errors/Error404.js6
-rw-r--r--src/main/js/src/containers/.gitkeep0
-rw-r--r--src/main/js/src/containers/Counter/actions.js12
-rw-r--r--src/main/js/src/containers/Counter/index.js68
-rw-r--r--src/main/js/src/containers/Counter/reducer.js24
-rw-r--r--src/main/js/src/containers/Counter/saga.js6
-rw-r--r--src/main/js/src/global-styles.css9
-rw-r--r--src/main/js/src/index.js14
-rw-r--r--src/main/js/src/reducers.js6
-rw-r--r--src/main/js/src/store.js38
-rw-r--r--src/main/js/yarn.lock39
-rw-r--r--src/main/resources/static/app.js3
29 files changed, 398 insertions, 125 deletions
diff --git a/build.gradle b/build.gradle
index d72cfc4f..9b5cee41 100644
--- a/build.gradle
+++ b/build.gradle
@@ -22,7 +22,7 @@ repositories {
dependencies {
compile 'com.google.code.gson:gson:2.8.0'
- compile 'ch.qos.logback:logback-classic:1.0.13'
+ compile 'ch.qos.logback:logback-classic:1.1.8'
compile 'org.springframework.boot:spring-boot-starter-websocket'
compile 'org.webjars:webjars-locator'
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) {
bgstack15