diff --git a/ui/.prettierrc b/ui/.prettierrc new file mode 100644 index 0000000..a5cd819 --- /dev/null +++ b/ui/.prettierrc @@ -0,0 +1,5 @@ +{ + "tabWidth": 2, + "useTabs": false, + "semi": true +} diff --git a/ui/Dockerfile b/ui/Dockerfile index 1a9d0d8..996fb37 100644 --- a/ui/Dockerfile +++ b/ui/Dockerfile @@ -8,9 +8,11 @@ FROM base as dependencies COPY pages /pages COPY public /public COPY styles /styles +COPY api /api COPY components /components COPY next* / COPY tsconfig.json / +COPY types.ts / EXPOSE 3000 RUN npm run build diff --git a/ui/api/game.api.ts b/ui/api/game.api.ts new file mode 100644 index 0000000..ca4b769 --- /dev/null +++ b/ui/api/game.api.ts @@ -0,0 +1,20 @@ +import wretch from "wretch"; +import { Cell } from "../types"; + +const USER_ID_HEADER = "Player-id"; + +export const fetchGameState = async ( + playerId: string, + gameId: number +): Promise<{ cells: Cell[]; cellWidth: number }> => { + const response: { board: Cell[][] } = await wretch(`/api/game/${gameId}`) + .headers({ + [USER_ID_HEADER]: playerId, + }) + .get() + .json(); + return { + cells: response.board.flat(), + cellWidth: response.board[0].length, + }; +}; diff --git a/ui/components/board.tsx b/ui/components/board.tsx index 52086a7..f6f4537 100644 --- a/ui/components/board.tsx +++ b/ui/components/board.tsx @@ -1,7 +1,25 @@ -import React from 'react' +import React from "react"; +import { Cell } from "../types"; +import styles from "../styles/board.module.css"; -const Board = () => ( - -) +interface BoardProps { + cells: Cell[]; + cellWidth: number; +} -export default Board; \ No newline at end of file +const Board = (props: BoardProps) => { + return ( +
+ {props.cells.map((cell) => ( +
{cell.piece}
+ ))} +
+ ); +}; + +export default Board; diff --git a/ui/components/game.tsx b/ui/components/game.tsx new file mode 100644 index 0000000..e6283d4 --- /dev/null +++ b/ui/components/game.tsx @@ -0,0 +1,28 @@ +import React, { useState, useEffect } from "react"; +import { fetchGameState } from "../api/game.api"; +import { Cell } from "../types"; +import Board from "./board"; + +interface GameProps { + gameId: number; +} + +const Game = (props: GameProps) => { + const [isLoading, setLoading] = useState(false); + const [cellWidth, setCellWidth] = useState(4); + const [cells, setCells] = useState([] as Cell[]); + useEffect(() => { + setLoading(true); + fetchGameState("red", props.gameId).then( + ({ cells: cellList, cellWidth: width }) => { + setCellWidth(width); + setCells(cellList); + setLoading(false); + } + ); + }, [props.gameId]); + + return ; +}; + +export default Game; diff --git a/ui/package-lock.json b/ui/package-lock.json index 1adaf33..227dea1 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -10,7 +10,8 @@ "dependencies": { "next": "12.1.0", "react": "17.0.2", - "react-dom": "17.0.2" + "react-dom": "17.0.2", + "wretch": "^1.7.9" }, "devDependencies": { "@types/node": "17.0.21", @@ -2527,6 +2528,11 @@ "dev": true, "license": "ISC" }, + "node_modules/wretch": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/wretch/-/wretch-1.7.9.tgz", + "integrity": "sha512-uUSze1Z72RiQjyoqr7r1KW+05WDNeqqKOeyJDPhw6EVEaOgp9RQNrr8AQt3OF7qylQbh2iVtT9r0nXIHlbJgqQ==" + }, "node_modules/yallist": { "version": "4.0.0", "dev": true, @@ -4060,6 +4066,11 @@ "version": "1.0.2", "dev": true }, + "wretch": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/wretch/-/wretch-1.7.9.tgz", + "integrity": "sha512-uUSze1Z72RiQjyoqr7r1KW+05WDNeqqKOeyJDPhw6EVEaOgp9RQNrr8AQt3OF7qylQbh2iVtT9r0nXIHlbJgqQ==" + }, "yallist": { "version": "4.0.0", "dev": true diff --git a/ui/package.json b/ui/package.json index a9ac96c..fe3cab8 100644 --- a/ui/package.json +++ b/ui/package.json @@ -11,7 +11,8 @@ "dependencies": { "next": "12.1.0", "react": "17.0.2", - "react-dom": "17.0.2" + "react-dom": "17.0.2", + "wretch": "^1.7.9" }, "devDependencies": { "@types/node": "17.0.21", diff --git a/ui/pages/index.tsx b/ui/pages/index.tsx index 3d7c124..0b16e8e 100644 --- a/ui/pages/index.tsx +++ b/ui/pages/index.tsx @@ -1,19 +1,19 @@ -import type { NextPage } from 'next' -import Head from 'next/head' -import Image from 'next/image' -import Board from '../components/board' -import styles from '../styles/Home.module.css' +import type { NextPage } from "next"; +import Head from "next/head"; +import Image from "next/image"; +import Game from "../components/game"; +import styles from "../styles/BoardPage.module.css"; const Home: NextPage = () => ( - <> +
Free Go Game
- +
- -) +
+); -export default Home \ No newline at end of file +export default Home; diff --git a/ui/styles/BoardPage.module.css b/ui/styles/BoardPage.module.css new file mode 100644 index 0000000..1e69efb --- /dev/null +++ b/ui/styles/BoardPage.module.css @@ -0,0 +1,4 @@ +.main { + max-width: 900px; + margin: auto; +} \ No newline at end of file diff --git a/ui/styles/board.module.css b/ui/styles/board.module.css new file mode 100644 index 0000000..ddf1ee2 --- /dev/null +++ b/ui/styles/board.module.css @@ -0,0 +1,8 @@ +.gridContainer { + display: grid; +} + +.gridCell { + border: 1px solid black; + padding-top: 100%; /* 100% is supposed to be 1:1 aspect ratio but it doesn't look like it */ +} \ No newline at end of file diff --git a/ui/types.ts b/ui/types.ts new file mode 100644 index 0000000..774c563 --- /dev/null +++ b/ui/types.ts @@ -0,0 +1,6 @@ +export interface Cell { + piece?: string; + terrain: boolean; + hidden: boolean; + empty: boolean; +} \ No newline at end of file