summaryrefslogtreecommitdiff
path: root/frontend/src/containers
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/containers')
-rw-r--r--frontend/src/containers/App/actions.js5
-rw-r--r--frontend/src/containers/App/constants.js1
-rw-r--r--frontend/src/containers/App/index.js83
-rw-r--r--frontend/src/containers/App/saga.js28
-rw-r--r--frontend/src/containers/GameBrowser/actions.js16
-rw-r--r--frontend/src/containers/GameBrowser/constants.js3
-rw-r--r--frontend/src/containers/GameBrowser/index.js31
-rw-r--r--frontend/src/containers/GameBrowser/reducer.js13
-rw-r--r--frontend/src/containers/GameBrowser/saga.js75
-rw-r--r--frontend/src/containers/HomePage/actions.js6
-rw-r--r--frontend/src/containers/HomePage/index.js39
-rw-r--r--frontend/src/containers/HomePage/saga.js57
-rw-r--r--frontend/src/containers/UserRepo/actions.js8
-rw-r--r--frontend/src/containers/UserRepo/reducer.js18
14 files changed, 383 insertions, 0 deletions
diff --git a/frontend/src/containers/App/actions.js b/frontend/src/containers/App/actions.js
new file mode 100644
index 00000000..cfb617d5
--- /dev/null
+++ b/frontend/src/containers/App/actions.js
@@ -0,0 +1,5 @@
+import { INITIALIZE_WS } from "./constants"
+
+export const initializeWs = () => ({
+ type: INITIALIZE_WS
+})
diff --git a/frontend/src/containers/App/constants.js b/frontend/src/containers/App/constants.js
new file mode 100644
index 00000000..be31f8cc
--- /dev/null
+++ b/frontend/src/containers/App/constants.js
@@ -0,0 +1 @@
+export const INITIALIZE_WS = 'app/INITIALIZE_WS'
diff --git a/frontend/src/containers/App/index.js b/frontend/src/containers/App/index.js
new file mode 100644
index 00000000..70f99b6b
--- /dev/null
+++ b/frontend/src/containers/App/index.js
@@ -0,0 +1,83 @@
+import React, { Component } from 'react'
+import { connect } from 'react-redux'
+import {
+ Banner,
+ Heading,
+ Space,
+ Button,
+ InlineForm,
+ Text
+} from 'rebass'
+import { Flex } from 'reflexbox'
+import Modal from '../../components/modals/username'
+import GameBrowser from '../GameBrowser'
+
+class App extends Component {
+ state = {
+ usernameModal: false,
+ }
+
+ componentDidMount() {
+
+ }
+
+ toggleModal = (key) => {
+ return (e) => {
+ const val = !this.state[key]
+ this.setState({ [key]: val })
+ }
+ }
+
+ createGame = (e) => {
+ e.preventDefault()
+ if (this._gameName !== undefined) {
+ this.props.createGame(this._gameName)
+ }
+ }
+
+ render() {
+ return (
+ <div>
+ <Banner
+ align="center"
+ style={{minHeight: '30vh'}}
+ backgroundImage="https://images.unsplash.com/photo-1431207446535-a9296cf995b1?dpr=1&auto=format&fit=crop&w=1199&h=799&q=80&cs=tinysrgb&crop="
+ >
+ <Heading level={1}>Seven Wonders</Heading>
+ </Banner>
+ <Flex align="center" p={1}>
+ <InlineForm
+ buttonLabel="Create Game"
+ label="Game name"
+ name="game_name"
+ onChange={(e) => this._gameName = e.target.value}
+ onClick={this.createGame}
+ >
+
+ </InlineForm>
+ <Space auto />
+ <Text><b>Username:</b> Cesar92</Text>
+ <Space x={1} />
+ <Button
+ onClick={this.toggleModal('usernameModal')}
+ children="Change"/>
+ </Flex>
+ <GameBrowser />
+ <Modal toggleModal={this.toggleModal} modalOpen={this.state.usernameModal} />
+ </div>
+ )
+ }
+}
+
+const mapStateToProps = (state) => ({
+
+})
+
+import { initializeWs } from "./actions";
+import { createGame } from '../GameBrowser/actions'
+const mapDispatchToProps = {
+ initializeWs,
+ createGame
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(App)
diff --git a/frontend/src/containers/App/saga.js b/frontend/src/containers/App/saga.js
new file mode 100644
index 00000000..0c212142
--- /dev/null
+++ b/frontend/src/containers/App/saga.js
@@ -0,0 +1,28 @@
+import { put, take } from 'redux-saga/effects'
+import { eventChannel } from 'redux-saga'
+
+function createSocketChannel(socket) {
+ return eventChannel(emit => {
+ const errorHandler = event => emit(JSON.parse(event.body))
+
+ const userErrors = socket.subscribe('/user/queue/errors', errorHandler)
+
+ const unsubscribe = () => {
+ userErrors.unsubscribe()
+ }
+
+ return unsubscribe
+ })
+}
+
+export function* watchOnErrors(socketConnection) {
+ const { socket } = socketConnection
+ const socketChannel = createSocketChannel(socket)
+
+ while (true) {
+ const payload = yield take(socketChannel)
+ yield put({ type: 'USER_ERROR', payload })
+ }
+}
+
+export default watchOnErrors
diff --git a/frontend/src/containers/GameBrowser/actions.js b/frontend/src/containers/GameBrowser/actions.js
new file mode 100644
index 00000000..376973b4
--- /dev/null
+++ b/frontend/src/containers/GameBrowser/actions.js
@@ -0,0 +1,16 @@
+import { NEW_GAME, JOIN_GAME, CREATE_GAME } from './constants'
+
+export const newGame = (game) => ({
+ type: NEW_GAME,
+ game
+})
+
+export const joinGame = (id) => ({
+ type: JOIN_GAME,
+ id
+})
+
+export const createGame = (name) => ({
+ type: CREATE_GAME,
+ name
+})
diff --git a/frontend/src/containers/GameBrowser/constants.js b/frontend/src/containers/GameBrowser/constants.js
new file mode 100644
index 00000000..36f701b7
--- /dev/null
+++ b/frontend/src/containers/GameBrowser/constants.js
@@ -0,0 +1,3 @@
+export const NEW_GAME = 'gameBrowser/NEW_GAME'
+export const JOIN_GAME = 'gameBrowser/JOIN_GAME'
+export const CREATE_GAME = 'gameBrowser/CREATE_GAME'
diff --git a/frontend/src/containers/GameBrowser/index.js b/frontend/src/containers/GameBrowser/index.js
new file mode 100644
index 00000000..9deb720b
--- /dev/null
+++ b/frontend/src/containers/GameBrowser/index.js
@@ -0,0 +1,31 @@
+import React, { Component } from 'react'
+import { connect } from 'react-redux'
+import { Flex } from 'reflexbox'
+import { Text, Space } from 'rebass'
+
+class GameBrowser extends Component {
+
+ listGames = (games) => {
+ return games.valueSeq().map((game, index) => {
+ return (<Flex key={index}>
+ <Text>{game.get('name')}</Text>
+ <Space auto />
+ <a href="#">Join</a>
+ </Flex>)
+ })
+ }
+
+ render() {
+ return (
+ <div>
+ {this.listGames(this.props.games)}
+ </div>
+ )
+ }
+}
+
+const mapStateToProps = (state) => ({
+ games: state.games
+})
+
+export default connect(mapStateToProps, {})(GameBrowser)
diff --git a/frontend/src/containers/GameBrowser/reducer.js b/frontend/src/containers/GameBrowser/reducer.js
new file mode 100644
index 00000000..4fb3390a
--- /dev/null
+++ b/frontend/src/containers/GameBrowser/reducer.js
@@ -0,0 +1,13 @@
+import { Map } from 'immutable'
+import { NEW_GAME } from './constants'
+
+const initialState = Map({})
+
+export default function reducer(state = initialState, action) {
+ switch (action.type) {
+ case NEW_GAME:
+ return state.set(action.game.get('id'), action.game)
+ default:
+ return state
+ }
+}
diff --git a/frontend/src/containers/GameBrowser/saga.js b/frontend/src/containers/GameBrowser/saga.js
new file mode 100644
index 00000000..4cd3d207
--- /dev/null
+++ b/frontend/src/containers/GameBrowser/saga.js
@@ -0,0 +1,75 @@
+import { call, put, take } from 'redux-saga/effects'
+import { eventChannel } from 'redux-saga'
+import { fromJS } from 'immutable'
+import { push } from 'react-router-redux'
+
+import { NEW_GAME, JOIN_GAME, CREATE_GAME } from './constants'
+import { newGame, joinGame } from './actions'
+
+function createSocketChannel(socket) {
+ return eventChannel(emit => {
+ const makeHandler = (type) => (event) => {
+ const response = fromJS(JSON.parse(event.body))
+
+ emit({
+ type,
+ response
+ })
+ }
+
+ const newGameHandler = makeHandler(NEW_GAME)
+ const joinGameHandler = makeHandler(JOIN_GAME)
+
+ const newGame = socket.subscribe('/topic/games', newGameHandler)
+ const joinGame = socket.subscribe('/user/queue/join-game', joinGameHandler)
+
+ const unsubscribe = () => {
+ newGame.unsubscribe()
+ joinGame.unsubscribe()
+ }
+
+ return unsubscribe
+ })
+}
+
+export function* watchGames(socketConnection) {
+
+ const { socket } = socketConnection
+ const socketChannel = createSocketChannel(socket)
+
+ while (true) {
+ const { type, response } = yield take(socketChannel)
+
+ switch (type) {
+ case NEW_GAME:
+ yield put(newGame(response))
+ break;
+ case JOIN_GAME:
+ yield put(joinGame(response))
+ break;
+ default:
+ console.error('Unknown type')
+ }
+ }
+}
+
+export function* createGame(socketConnection) {
+ const { name } = yield take(CREATE_GAME)
+ const { socket } = socketConnection
+
+ socket.send("/app/lobby/create-game", JSON.stringify({
+ 'gameName': name,
+ 'playerName': 'Cesar92'
+ }), {})
+}
+
+export function* gameBrowserSaga(socketConnection) {
+ yield put(push('/lobby'))
+
+ yield [
+ call(watchGames, socketConnection),
+ call(createGame, socketConnection)
+ ]
+}
+
+export default gameBrowserSaga
diff --git a/frontend/src/containers/HomePage/actions.js b/frontend/src/containers/HomePage/actions.js
new file mode 100644
index 00000000..e06d6fa2
--- /dev/null
+++ b/frontend/src/containers/HomePage/actions.js
@@ -0,0 +1,6 @@
+export const ENTER_GAME = 'homePage/ENTER_GAME'
+
+export const enterGame = (username) => ({
+ type: ENTER_GAME,
+ username
+})
diff --git a/frontend/src/containers/HomePage/index.js b/frontend/src/containers/HomePage/index.js
new file mode 100644
index 00000000..c8e33239
--- /dev/null
+++ b/frontend/src/containers/HomePage/index.js
@@ -0,0 +1,39 @@
+import React, { Component } from 'react'
+import { connect } from 'react-redux'
+import { Heading, InlineForm } from 'rebass'
+
+class HomePage extends Component {
+
+ play = (e) => {
+ e.preventDefault()
+ if (this._username !== undefined) {
+ this.props.enterGame(this._username)
+ }
+ }
+
+ render() {
+ return (
+ <div>
+ <Heading>Enter your username to start playing!</Heading>
+ <InlineForm
+ buttonLabel="Play now!"
+ label="Username"
+ name="username"
+ onChange={(e) => this._username = e.target.value}
+ onClick={this.play}
+ />
+ </div>
+ )
+ }
+}
+
+const mapStateToProps = (state) => ({
+
+})
+
+import { enterGame } from './actions'
+const mapDispatchToProps = {
+ enterGame
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(HomePage)
diff --git a/frontend/src/containers/HomePage/saga.js b/frontend/src/containers/HomePage/saga.js
new file mode 100644
index 00000000..0fbe8a45
--- /dev/null
+++ b/frontend/src/containers/HomePage/saga.js
@@ -0,0 +1,57 @@
+import { call, put, take } from 'redux-saga/effects'
+import { eventChannel } from 'redux-saga'
+import { ENTER_GAME } from './actions'
+import { setUsername } from '../UserRepo/actions'
+
+import gameBrowserSaga from '../GameBrowser/saga'
+
+function* sendUsername(socketConnection) {
+ const { username: playerName } = yield take(ENTER_GAME)
+ const { socket } = socketConnection
+
+ socket.send("/app/chooseName", JSON.stringify({
+ playerName
+ }), {})
+}
+
+function createSocketChannel(socket) {
+ return eventChannel(emit => {
+ const receiveUsername = socket.subscribe('/user/queue/nameChoice', event => {
+ emit(JSON.parse(event.body))
+ })
+
+ const unsubscribe = () => {
+ receiveUsername.unsubscribe()
+ }
+
+ return unsubscribe
+ })
+}
+
+function* validateUsername(socketConnection) {
+ const { socket } = socketConnection
+ const socketChannel = createSocketChannel(socket)
+
+ const response = yield take(socketChannel)
+
+ if (response.error) {
+ return false
+ }
+
+ yield put(setUsername(response.userName, response.displayName, response.index))
+ yield call(gameBrowserSaga, socketConnection)
+ return true
+}
+
+function* homeSaga(socketConnection) {
+ let validated = false
+ do {
+ const [, usernameValid] = yield [
+ call(sendUsername, socketConnection),
+ call(validateUsername, socketConnection)
+ ]
+ validated = usernameValid
+ } while (!validated)
+}
+
+export default homeSaga
diff --git a/frontend/src/containers/UserRepo/actions.js b/frontend/src/containers/UserRepo/actions.js
new file mode 100644
index 00000000..dc06035b
--- /dev/null
+++ b/frontend/src/containers/UserRepo/actions.js
@@ -0,0 +1,8 @@
+export const SET_USERNAME = 'homePage/SET_USERNAME'
+
+export const setUsername = (userName, displayName, index) => ({
+ type: SET_USERNAME,
+ userName,
+ index,
+ displayName
+})
diff --git a/frontend/src/containers/UserRepo/reducer.js b/frontend/src/containers/UserRepo/reducer.js
new file mode 100644
index 00000000..82960a58
--- /dev/null
+++ b/frontend/src/containers/UserRepo/reducer.js
@@ -0,0 +1,18 @@
+import { SET_USERNAME } from './actions'
+import { fromJS } from 'immutable'
+const initialState = fromJS({
+ username: '',
+ displayName: '',
+ id: null
+})
+
+export default (state = initialState, action) => {
+ switch (action.type) {
+ case SET_USERNAME:
+ return state.set('username', action.userName)
+ .set('displayName', action.displayName)
+ .set('id', action.index)
+ default:
+ return state
+ }
+}
bgstack15