diff options
Diffstat (limited to 'sw-ui-kt/src/main/kotlin')
6 files changed, 173 insertions, 13 deletions
diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/CreateGameForm.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/CreateGameForm.kt new file mode 100644 index 00000000..318f49f4 --- /dev/null +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/CreateGameForm.kt @@ -0,0 +1,49 @@ +package org.luxons.sevenwonders.ui.components.gameBrowser + +import kotlinx.html.InputType +import kotlinx.html.js.onChangeFunction +import kotlinx.html.js.onSubmitFunction +import org.luxons.sevenwonders.ui.redux.RequestCreateGameAction +import org.luxons.sevenwonders.ui.redux.connectDispatch +import org.w3c.dom.HTMLInputElement +import react.RBuilder +import react.RClass +import react.RComponent +import react.RProps +import react.RState +import react.dom.* + +private interface CreateGameFormProps: RProps { + var createGame: (String) -> Unit +} + +private data class CreateGameFormState(var gameName: String = ""): RState + +private class CreateGameForm(props: CreateGameFormProps): RComponent<CreateGameFormProps, CreateGameFormState>(props) { + + override fun CreateGameFormState.init(props: CreateGameFormProps) { + gameName = "" + } + + override fun RBuilder.render() { + form { + attrs.onSubmitFunction = { props.createGame(state.gameName) } + + input(type = InputType.text) { + attrs { + value = state.gameName + onChangeFunction = { e -> + val input = e.currentTarget as HTMLInputElement + setState(transformState = { CreateGameFormState(input.value) }) + } + } + } + + input(type = InputType.submit) {} + } + } +} + +val createGameForm: RClass<RProps> = connectDispatch(CreateGameForm::class) { dispatch, _ -> + createGame = { name -> dispatch(RequestCreateGameAction(name)) } +} diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt index 73c11984..fc7e12d5 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt @@ -5,4 +5,6 @@ import react.dom.* fun RBuilder.gameBrowser() = div { h1 { +"Games" } + createGameForm {} + gameList {} } diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameList.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameList.kt new file mode 100644 index 00000000..40ad826a --- /dev/null +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameList.kt @@ -0,0 +1,83 @@ +package org.luxons.sevenwonders.ui.components.gameBrowser + +import kotlinx.html.js.onClickFunction +import org.luxons.sevenwonders.model.api.LobbyDTO +import org.luxons.sevenwonders.model.api.State +import org.luxons.sevenwonders.ui.redux.RequestJoinGameAction +import org.luxons.sevenwonders.ui.redux.connect +import react.RBuilder +import react.RComponent +import react.RProps +import react.RState +import react.dom.* + +interface GameListStateProps : RProps { + var games: List<LobbyDTO> +} + +interface GameListDispatchProps: RProps { + var joinGame: (Long) -> Unit +} + +interface GameListProps : GameListStateProps, GameListDispatchProps + +class GameListPresenter(props: GameListProps) : RComponent<GameListProps, RState>(props) { + + override fun RBuilder.render() { + table { + thead { + gameListHeaderRow() + } + tbody { + props.games.map { + gameListItemRow(it, props.joinGame) + } + } + } + } +} + +private fun RBuilder.gameListHeaderRow() = tr { + th { +"Name" } + th { +"Status" } + th { +"Nb Players" } + th { +"Join" } +} + +private fun RBuilder.gameListItemRow(lobby: LobbyDTO, joinGame: (Long) -> Unit) = tr { + th { +lobby.name } + th { gameStatus(lobby.state) } + th { playerCount(lobby.players.size) } + th { joinButton(lobby, joinGame) } +} + +private fun RBuilder.gameStatus(state: State) { + span { + +state.toString() + } +} + +private fun RBuilder.playerCount(nPlayers: Int) { + span { + +nPlayers.toString() + } +} + +private fun RBuilder.joinButton(lobby: LobbyDTO, joinGame: (Long) -> Unit) { + button { + attrs { + disabled = lobby.state != State.LOBBY + onClickFunction = { joinGame(lobby.id) } + } + } +} + +val gameList = connect<GameListStateProps, GameListDispatchProps, GameListProps>( + clazz = GameListPresenter::class, + mapStateToProps = { state, _ -> + games = state.games + }, + mapDispatchToProps = { dispatch, _ -> + joinGame = { gameId -> dispatch(RequestJoinGameAction(gameId = gameId)) } + } +) diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt index f9f5a26d..21fc7480 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt @@ -1,8 +1,19 @@ package org.luxons.sevenwonders.ui.redux +import org.luxons.sevenwonders.model.api.LobbyDTO +import org.luxons.sevenwonders.model.api.PlayerDTO import redux.RAction +data class SwState( + val player: PlayerDTO? = null, + val lobby: LobbyDTO? = null, + val games: List<LobbyDTO> = emptyList() +) + fun rootReducer(state: SwState, action: RAction) = when (action) { - is RequestChooseName -> state.copy(playerName = action.playerName) + is SetCurrentPlayerAction -> state.copy(player = action.player) + is UpdateGameListAction -> state.copy(games = action.games) + is UpdateLobbyAction -> state.copy(lobby = action.lobby) + is UpdatePlayers -> TODO() else -> state } diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Store.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Store.kt index fea13f04..44237794 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Store.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Store.kt @@ -9,11 +9,7 @@ import redux.compose import redux.createStore import redux.rEnhancer -data class SwState( - val playerName: String -) - -val INITIAL_STATE = SwState("Bob") +val INITIAL_STATE = SwState() fun configureStore( sagaManager: SagaManager<SwState, RAction, WrapperAction>, diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Utils.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Utils.kt index e40e11bc..dc85d358 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Utils.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Utils.kt @@ -10,12 +10,31 @@ import redux.RAction import redux.WrapperAction import kotlin.reflect.KClass -inline fun <reified T : RProps> connectDispatch( - clazz: KClass<out RComponent<T, out RState>>, - crossinline mapDispatchToProps: T.((RAction) -> WrapperAction, RProps) -> Unit +inline fun <reified DP : RProps> connectDispatch( + clazz: KClass<out RComponent<DP, out RState>>, + noinline mapDispatchToProps: DP.((RAction) -> WrapperAction, RProps) -> Unit ): RClass<RProps> { - val connect = rConnect<RAction, WrapperAction, RProps, T>(mapDispatchToProps = { dispatch, ownProps -> - mapDispatchToProps(dispatch, ownProps) - }) - return connect.invoke(clazz.js.unsafeCast<RClass<T>>()) + val connect = rConnect(mapDispatchToProps = mapDispatchToProps) + return connect.invoke(clazz.js.unsafeCast<RClass<DP>>()) +} + +inline fun <reified SP : RProps> connectState( + clazz: KClass<out RComponent<SP, out RState>>, + noinline mapStateToProps: SP.(SwState, RProps) -> Unit +): RClass<RProps> { + val connect = rConnect(mapStateToProps = mapStateToProps) + return connect.invoke(clazz.js.unsafeCast<RClass<SP>>()) +} + + +inline fun <reified SP : RProps, reified DP : RProps, reified P : RProps> connect( + clazz: KClass<out RComponent<P, out RState>>, + noinline mapStateToProps: SP.(SwState, RProps) -> Unit, + noinline mapDispatchToProps: DP.((RAction) -> WrapperAction, RProps) -> Unit +): RClass<RProps> { + val connect = rConnect<SwState, RAction, WrapperAction, RProps, SP, DP, P>( + mapStateToProps = mapStateToProps, + mapDispatchToProps = mapDispatchToProps + ) + return connect.invoke(clazz.js.unsafeCast<RClass<P>>()) } |