Skip to content

Commit

Permalink
More files to typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
fernandosouza committed Aug 1, 2020
1 parent b5a332a commit c3fc2dc
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/App.test.js
@@ -1,7 +1,7 @@
import '../testHelpers/LocalStorageMock';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import App from './App.tsx';
import { MemoryRouter as Router } from 'react-router-dom';
import TicTacToe from './ticTacToe/TicTacToe';

Expand Down
42 changes: 33 additions & 9 deletions src/App.js → src/App.tsx
@@ -1,26 +1,50 @@
import React, { Component } from 'react';
import React, { Component, ContextType } from 'react';
import Board from './board/Board';
import Storage from './storage/Storage';
import { Link } from 'react-router-dom';
import './App.scss';
import { GameContext } from './GameContext';
import Player from './ticTacToe/Player';
import { GameBoard } from './ticTacToe/TicTacToe';

interface AppProps {
match: {
params: {
firstPlayer: string,
secondPlayer: string
}
}
}
interface AppState {
winner: {
player: Player | null
},
filledSlots: GameBoard | null
winnerSlots: Player[] | null
}

/**
* Initialize the game asking for players information. Manage players
* turns and set in the board filled slots.
* @author Fernando Souza nandosouzafilho@gmail.com
**/
class App extends Component {
// ITicTacToe
class App extends Component<AppProps, AppState> {
static contextType = GameContext;
context!: ContextType<typeof GameContext>;
private storage: Storage;

constructor(props) {
constructor(props: AppProps) {
super(props);

this.state = {
winner: {
player: null
},
filledSlots: null,
winnerSlots: []
};
this.storage_ = new Storage();
this.storage = new Storage();
}

componentDidMount() {
Expand All @@ -29,7 +53,7 @@ class App extends Component {
}

this.setState({
filledSlots: new Map(this.context.game.getBoard())
filledSlots: this.context.game.getBoard()
});
}

Expand All @@ -39,8 +63,8 @@ class App extends Component {
**/
setPlayersFromURL_() {
const { firstPlayer, secondPlayer } = this.props.match.params;
this.context.game.playersManager_.addPlayer(firstPlayer);
this.context.game.playersManager_.addPlayer(secondPlayer);
this.context.game.playersManager.addPlayer(firstPlayer);
this.context.game.playersManager.addPlayer(secondPlayer);
}

/**
Expand All @@ -49,7 +73,7 @@ class App extends Component {
* @private
**/
hasNoPlayers_() {
return this.context.game.playersManager_
return this.context.game.playersManager
.checkErros()
.some(error => error.code === 'no_players');
}
Expand All @@ -59,7 +83,7 @@ class App extends Component {
**/
render() {
const leaderboardMessage = () => {
if (this.state.winner) {
if (this.state.winner.player) {
return (
<p className="winner-message">
Congratulations {this.state.winner.player.name}. <Link to="/leaderboard">
Expand Down
4 changes: 2 additions & 2 deletions src/GameContext.tsx
@@ -1,8 +1,8 @@
import { createContext } from 'react';
import TicTacToe from './ticTacToe/TicTacToe';
import TicTacToe, { ITicTacToe } from './ticTacToe/TicTacToe';

export const GameContext = createContext<{
game: TicTacToe | null
game: ITicTacToe
}>({
game: new TicTacToe()
});
Expand Down
4 changes: 2 additions & 2 deletions src/board/Slot.tsx
Expand Up @@ -16,7 +16,7 @@ const scale = keyframes`
}
`;

const Player1 = styled(X) <{ winner?: boolean }>`
const Player1 = styled(X) <{ winner: boolean }>`
width: 100px;
height: 100px;
Expand All @@ -25,7 +25,7 @@ const Player1 = styled(X) <{ winner?: boolean }>`
`}
`

const Player2 = styled(Circle) <{ winner?: boolean }>`
const Player2 = styled(Circle) <{ winner: boolean }>`
width: 100px;
height: 100px;
Expand Down
2 changes: 1 addition & 1 deletion src/index.js → src/index.tsx
Expand Up @@ -3,6 +3,6 @@ import ReactDOM from 'react-dom';
import Routes from './routes/Routes';

ReactDOM.render(
<Routes />,
<React.StrictMode><Routes /></React.StrictMode>,
document.getElementById('root')
);
2 changes: 1 addition & 1 deletion src/routes/Routes.js
@@ -1,5 +1,5 @@
import React from 'react';
import App from '../App';
import App from '../App.tsx';
import Setup from '../setup/Setup';
import LeaderBoard from '../leaderBoard/LeaderBoard';
import {
Expand Down
2 changes: 1 addition & 1 deletion src/routes/Routes.test.js
@@ -1,7 +1,7 @@
import React from 'react';
import { shallow } from 'enzyme';
import { Route } from 'react-router-dom';
import App from '../App';
import App from '../App.tsx';
import Setup from '../setup/Setup';
import LeaderBoard from '../leaderBoard/LeaderBoard';
import Routes from './Routes';
Expand Down
12 changes: 9 additions & 3 deletions src/storage/Storage.js → src/storage/Storage.tsx
@@ -1,16 +1,22 @@
class Storage {
private storageName: string;

constructor(storageName = 'gameLeaderBoard', initialValue = '[]') {
this.storageName = storageName;
if (!localStorage.getItem(storageName)) {
localStorage.setItem(storageName, initialValue);
}
}

getData() {
return JSON.parse(localStorage.getItem(this.storageName));
getData<V>(): V | null {
const storedData = localStorage.getItem(this.storageName);
if (storedData) {
return JSON.parse(storedData || '');
}
return null;
}

update(data) {
update(data: any) {
localStorage.setItem(this.storageName, JSON.stringify(data));
}
}
Expand Down
12 changes: 10 additions & 2 deletions src/ticTacToe/PlayersManager.ts
Expand Up @@ -4,11 +4,19 @@ interface PlayerManagerError {
code: string
}

export interface IPlayersManager {
checkErros: () => PlayerManagerError[]
addPlayer: (playerName: string) => void;
getCurrentPlayer: () => Player;
nextPlayerTurn: () => Player;
switchPlayer: (playerIndex: number) => Player;
}

/**
* Manages players providing a public API for adding players and sets which one
* is in the turn.
**/
class PlayersManager {
class PlayersManager implements IPlayersManager {
private erros_: PlayerManagerError[] = [];
private players_: Player[] = [];
private currentPlayerIndex_ = 0;
Expand Down Expand Up @@ -36,7 +44,7 @@ class PlayersManager {
* Checks if there are erros regarding players.
* @returns {Array} Array of errors
**/
checkErros() {
checkErros(): PlayerManagerError[] {
this.erros_ = [];
if (!this.players_.length) {
this.erros_.push({ code: 'no_players' });
Expand Down
37 changes: 22 additions & 15 deletions src/ticTacToe/TicTacToe.ts
@@ -1,20 +1,27 @@
import PlayersManager from './PlayersManager';
import PlayersManager, { IPlayersManager } from './PlayersManager';
import Player from './Player';
import { EventEmitter } from './EventEmitter';

export type WinnerSlots = { player: Player, slots: any }
export type WinnerSlots = { player: Player, slots: any };
export type GameBoard = Map<any, any>;
export interface ITicTacToe extends EventEmitter {
fillSlot: (index: number) => void,
getBoard: () => GameBoard
clearBoard: () => void;
playersManager: IPlayersManager;
};

class TicTacToe extends EventEmitter {
private board_: Map<any, any>;
private playersManager_: PlayersManager;
class TicTacToe extends EventEmitter implements ITicTacToe {
private board_: GameBoard;
playersManager: IPlayersManager;

constructor(playerOne?: string, playerTwo?: string) {
super();
this.board_ = new Map();
this.playersManager_ = new PlayersManager();
this.playersManager = new PlayersManager();
if (playerOne && playerTwo) {
this.playersManager_.addPlayer(playerOne);
this.playersManager_.addPlayer(playerTwo);
this.playersManager.addPlayer(playerOne);
this.playersManager.addPlayer(playerTwo);
}
}

Expand Down Expand Up @@ -93,7 +100,7 @@ class TicTacToe extends EventEmitter {
* @param {Number} currentPlayerId The player id.
* @private
**/
checkSlot_(index: Number, currentPlayerId: number) {
checkSlot_(index: number, currentPlayerId: number) {
return this.board_.get(index) === currentPlayerId;
}

Expand All @@ -102,8 +109,8 @@ class TicTacToe extends EventEmitter {
* if it has, do not call the next game turn and end the game.
* @param {Number} index the slot index.
**/
fillSlot(index: Number) {
let currentPlayer_ = this.playersManager_.getCurrentPlayer();
fillSlot(index: number) {
let currentPlayer_ = this.playersManager.getCurrentPlayer();
if (this.board_.get(index)) {
return;
}
Expand All @@ -118,16 +125,16 @@ class TicTacToe extends EventEmitter {
if (winner || this.board_.size === 9) {
this.dispatch('gameEnd', winner);
} else {
this.playersManager_.nextPlayerTurn();
this.playersManager.nextPlayerTurn();
}
}

/**
* Returns the list of filled slots.
* @returns {Map<Object>} The game board.
**/
getBoard() {
return this.board_;
getBoard(): GameBoard {
return new Map(this.board_);
}

clearBoard() {
Expand All @@ -140,7 +147,7 @@ class TicTacToe extends EventEmitter {
* @private
**/
getWinner_(): WinnerSlots | undefined {
let currentPlayer = this.playersManager_.getCurrentPlayer();
let currentPlayer = this.playersManager.getCurrentPlayer();
let playerId = currentPlayer.id;
let hasWinner =
this.checkLines_(playerId) ||
Expand Down

0 comments on commit c3fc2dc

Please sign in to comment.