Skip to content

Commit 89a4f1b

Browse files
RobbyTiptonfscgoldenjoeeparkdavidkim7773khobread
committed
Added demo application.
Co-authored-by: Chris LeBrett <[email protected]> Co-authored-by: Robby Tipton <[email protected]> Co-authored-by: Joseph Park <[email protected]> Co-authored-by: David Kim <[email protected]> Co-authored-by: Kevin HoEun Lee <[email protected]>
1 parent 61bd748 commit 89a4f1b

File tree

16 files changed

+605
-0
lines changed

16 files changed

+605
-0
lines changed

demo-app/.babelrc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
{
3+
"presets": [
4+
"@babel/preset-env",
5+
"@babel/preset-react"
6+
]
7+
}

demo-app/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

demo-app/package.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"name": "typescript-module",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"start": "nodemon ./src/server/server.ts & webpack-dev-server",
8+
"test": "echo \"Error: no test specified\" && exit 1"
9+
},
10+
"repository": {
11+
"type": "git",
12+
"url": "git+https://github.com/CodesmithLLC/typescript-module.git"
13+
},
14+
"author": "Allison Pratt ([email protected])",
15+
"license": "ISC",
16+
"bugs": {
17+
"url": "https://github.com/CodesmithLLC/typescript-module/issues"
18+
},
19+
"homepage": "https://github.com/CodesmithLLC/typescript-module#readme",
20+
"devDependencies": {
21+
"@babel/core": "^7.16.7",
22+
"@babel/preset-env": "^7.16.7",
23+
"@babel/preset-react": "^7.16.7",
24+
"@types/express": "^4.17.13",
25+
"@types/node": "^17.0.8",
26+
"@types/react": "^17.0.38",
27+
"@types/react-dom": "^17.0.11",
28+
"babel-loader": "^8.2.3",
29+
"copy-webpack-plugin": "^10.2.0",
30+
"css-loader": "^6.5.1",
31+
"html-webpack-plugin": "^5.5.0",
32+
"nodemon": "^2.0.15",
33+
"ts-loader": "^9.2.6",
34+
"typescript": "^4.5.4",
35+
"webpack": "^5.65.0",
36+
"webpack-cli": "^4.9.1",
37+
"webpack-dev-server": "^4.7.2"
38+
},
39+
"dependencies": {
40+
"express": "^4.17.2",
41+
"react": "^18.1.0",
42+
"react-dom": "^18.1.0",
43+
"react-router-dom": "^6.3.0",
44+
"ts-node": "^10.4.0"
45+
}
46+
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import React, { Component } from 'react';
2+
import Row from './Row';
3+
import { BoardText, BoardContent, Scoreboard, Player } from './../../types';
4+
5+
type BoardState = {
6+
board: BoardContent;
7+
currentPlayer: Player;
8+
gameOver: boolean;
9+
message: string;
10+
scoreboard: Scoreboard;
11+
};
12+
13+
class Board extends Component<{}, BoardState> {
14+
constructor(props: any) {
15+
super(props);
16+
this.state = {
17+
board: this.newBoard(),
18+
currentPlayer: 'X',
19+
gameOver: false,
20+
message: '',
21+
scoreboard: { X: 0, O: 0 },
22+
};
23+
24+
// these methods need to be bound to the context of `this` since
25+
// these will be passed into event handlers and called from outside the object
26+
// where the context of `this` would be otherwise different
27+
this.resetBoard = this.resetBoard.bind(this);
28+
this.handleBoxClick = this.handleBoxClick.bind(this);
29+
}
30+
31+
componentDidMount() {
32+
this.getScores();
33+
}
34+
35+
componentDidUpdate() {
36+
this.checkForWinner();
37+
}
38+
39+
/**
40+
* @method newBoard
41+
* @description - returns a blank BoardContent array,
42+
* for the start of a new game
43+
*/
44+
newBoard(): BoardContent {
45+
return [
46+
['-', '-', '-'],
47+
['-', '-', '-'],
48+
['-', '-', '-'],
49+
];
50+
}
51+
52+
/**
53+
* @method resetBoard
54+
* @description - sets to board object to be all '-',
55+
* and sets gameOver and message to default state
56+
*/
57+
resetBoard(): void {
58+
this.setState({
59+
gameOver: false,
60+
board: this.newBoard(),
61+
message: '',
62+
});
63+
}
64+
65+
/**
66+
* @method checkForWinner
67+
* @description - checks to see if either player has filled a row
68+
* if so, ends the game and updates the message to declare winner
69+
*/
70+
checkForWinner(): void {
71+
const { board, gameOver, currentPlayer } = this.state;
72+
73+
// helper function to check if board is filled
74+
const spacesLeft = (): boolean => {
75+
for (let i of board) {
76+
if (i.includes('-')) return true;
77+
}
78+
return false;
79+
};
80+
81+
if (!gameOver) {
82+
// win conditions: matching rows, columns, or diagonals, that are not empty('-')
83+
if (
84+
(board[0][0] === board[0][1] &&
85+
board[0][1] === board[0][2] &&
86+
board[0][2] !== '-') ||
87+
(board[1][0] === board[1][1] &&
88+
board[1][1] === board[1][2] &&
89+
board[1][2] !== '-') ||
90+
(board[2][0] === board[2][1] &&
91+
board[2][1] === board[2][2] &&
92+
board[2][2] !== '-') ||
93+
(board[0][0] === board[1][0] &&
94+
board[1][0] === board[2][0] &&
95+
board[2][0] !== '-') ||
96+
(board[0][1] === board[1][1] &&
97+
board[1][1] === board[2][1] &&
98+
board[2][1] !== '-') ||
99+
(board[0][2] === board[1][2] &&
100+
board[1][2] === board[2][2] &&
101+
board[2][2] !== '-') ||
102+
(board[0][0] === board[1][1] &&
103+
board[1][1] === board[2][2] &&
104+
board[2][2] !== '-') ||
105+
(board[2][0] === board[1][1] &&
106+
board[1][1] === board[0][2] &&
107+
board[0][2] !== '-')
108+
) {
109+
// winner is the person who's turn was previous
110+
const winner: Player = currentPlayer === 'X' ? 'O' : 'X';
111+
112+
this.setState({
113+
gameOver: true,
114+
message: `Player ${winner} wins!`,
115+
});
116+
117+
this.getScores('POST', JSON.stringify({ winner }));
118+
119+
// draw condition: no '-' remaining in board without above win condition triggering
120+
} else if (!spacesLeft()) {
121+
this.setState({
122+
gameOver: true,
123+
message: 'Draw!',
124+
});
125+
}
126+
}
127+
}
128+
129+
getScores(method?: string, winner?: string) {
130+
// If method is GET, send a GET request to api route to get scores.
131+
// If method is POST, send a POST request to api route to post the scores.
132+
}
133+
134+
handleBoxClick(row: number, column: number): void {
135+
const boardCopy: BoardContent = [
136+
[...this.state.board[0]],
137+
[...this.state.board[1]],
138+
[...this.state.board[2]],
139+
];
140+
boardCopy[row][column] = this.state.currentPlayer;
141+
const newPlayer: Player = this.state.currentPlayer === 'X' ? 'O' : 'X';
142+
this.setState({ board: boardCopy, currentPlayer: newPlayer });
143+
}
144+
145+
render() {
146+
// insert logic to render rows here
147+
const rows: Array<JSX.Element> = [];
148+
for (let i = 0; i < 3; i++) {
149+
rows.push(
150+
<Row
151+
key={i}
152+
row={i}
153+
handleBoxClick={this.handleBoxClick}
154+
values={this.state.board[i]}
155+
/>
156+
);
157+
}
158+
// Destructure scores for X and O from state so that they can individually be rendered below
159+
const { X, O }: Scoreboard = this.state.scoreboard;
160+
161+
return (
162+
<div className="board">
163+
<h1>Tic Tac Toe</h1>
164+
{this.state.gameOver && <h4>{this.state.message}</h4>}
165+
{rows}
166+
<button id="reset" onClick={this.resetBoard}>
167+
Reset
168+
</button>
169+
</div>
170+
);
171+
}
172+
}
173+
174+
export default Board;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react';
2+
import { BoardText } from '../../types';
3+
4+
type BoxProps = {
5+
value: BoardText;
6+
row: number;
7+
column: number;
8+
handleBoxClick: (row: number, column: number) => void;
9+
};
10+
11+
const Box = (props: BoxProps) => {
12+
return (
13+
<button
14+
className="box"
15+
onClick={(e) => props.handleBoxClick(props.row, props.column)}
16+
>
17+
{props.value}
18+
</button>
19+
);
20+
};
21+
22+
export default Box;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from "react";
2+
import Increment from "./Increment";
3+
4+
function Buttons() {
5+
const buttons = [];
6+
for (let i = 0; i < 4; i++){
7+
buttons.push(<Increment />)
8+
}
9+
10+
return(
11+
<div className="buttons">
12+
<h1>Stateful Buttons</h1>
13+
<h4>These buttons are functional components that each manage their own state with the useState hook.</h4>
14+
{buttons}
15+
</div>
16+
)
17+
}
18+
19+
export default Buttons;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React from 'react';
2+
3+
function Home() {
4+
return (
5+
<div className="about">
6+
<h1>Lorem Ipsum</h1>
7+
<p>
8+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
9+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
10+
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
11+
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
12+
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
13+
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
14+
mollit anim id est laborum."
15+
</p>
16+
<p>
17+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
18+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
19+
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
20+
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
21+
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
22+
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
23+
mollit anim id est laborum."
24+
</p>
25+
</div>
26+
);
27+
}
28+
29+
export default Home;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React, { useState } from 'react';
2+
3+
function Increment() {
4+
const [count, setCount] = useState(0);
5+
6+
return (
7+
<button className="increment" onClick={() => setCount(count + 1)}>
8+
You clicked me {count} times.
9+
</button>
10+
);
11+
}
12+
13+
export default Increment;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from "react";
2+
import { Link } from "react-router-dom";
3+
4+
function Nav() {
5+
return(
6+
<div className="nav">
7+
<Link className="link" to="/">About</Link>
8+
<Link id="tictactoe" className="link" to="/tictactoe">Tic-Tac-Toe</Link>
9+
<Link className="link" to="/buttons">Counter</Link>
10+
</div>
11+
)
12+
}
13+
14+
export default Nav;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react';
2+
import Box from './Box';
3+
import { BoardText } from '../../types';
4+
5+
type RowProps = {
6+
handleBoxClick: (row: number, column: number) => void;
7+
values: Array<BoardText>;
8+
row: number;
9+
};
10+
11+
const Row = (props: RowProps) => {
12+
const boxes: Array<JSX.Element> = [];
13+
for (let i = 0; i < 3; i++) {
14+
boxes.push(
15+
<Box
16+
key={i}
17+
row={props.row}
18+
column={i}
19+
handleBoxClick={props.handleBoxClick}
20+
value={props.values[i]}
21+
></Box>
22+
);
23+
}
24+
25+
return <div className="row">{boxes}</div>;
26+
};
27+
28+
export default Row;

0 commit comments

Comments
 (0)