diff --git a/ui/Dockerfile b/ui/Dockerfile
index 996fb37..4b535fe 100644
--- a/ui/Dockerfile
+++ b/ui/Dockerfile
@@ -5,6 +5,7 @@ COPY package-lock.json .
RUN npm install
FROM base as dependencies
+COPY utils /utils
COPY pages /pages
COPY public /public
COPY styles /styles
diff --git a/ui/api/game.api.ts b/ui/api/game.api.ts
index ca4b769..018fb9b 100644
--- a/ui/api/game.api.ts
+++ b/ui/api/game.api.ts
@@ -1,5 +1,5 @@
import wretch from "wretch";
-import { Cell } from "../types";
+import { Cell, Position } from "../types";
const USER_ID_HEADER = "Player-id";
@@ -18,3 +18,27 @@ export const fetchGameState = async (
cellWidth: response.board[0].length,
};
};
+
+export const submitMove = async (
+ playerId: string,
+ gameId: number,
+ piecePosition: Position,
+ movePosition: Position
+): Promise<{ cells: Cell[] }> => {
+ console.log(piecePosition, movePosition);
+ const response: { board: Cell[][] } = await wretch(`/api/game/${gameId}/move`)
+ .headers({
+ [USER_ID_HEADER]: playerId,
+ })
+ .body({
+ pieceRow: piecePosition.row,
+ pieceColumn: piecePosition.column,
+ moveRow: movePosition.row,
+ moveColumn: movePosition.column,
+ })
+ .post()
+ .json();
+ return {
+ cells: response.board.flat(),
+ };
+};
diff --git a/ui/components/board.tsx b/ui/components/board.tsx
index f6f4537..86432c7 100644
--- a/ui/components/board.tsx
+++ b/ui/components/board.tsx
@@ -1,25 +1,33 @@
-import React from "react";
+import React, { useState } from "react";
+import cn from "classnames";
import { Cell } from "../types";
import styles from "../styles/board.module.css";
interface BoardProps {
cells: Cell[];
cellWidth: number;
+ focusedCellIndex?: number;
+ onCellClick: (index: number) => void;
}
-const Board = (props: BoardProps) => {
- return (
-
- {props.cells.map((cell) => (
-
{cell.piece}
- ))}
-
- );
-};
+const Board = (props: BoardProps) => (
+
+ {props.cells.map((cell, i) => (
+
+ ))}
+
+);
export default Board;
diff --git a/ui/components/game.tsx b/ui/components/game.tsx
index e6283d4..78e3c3a 100644
--- a/ui/components/game.tsx
+++ b/ui/components/game.tsx
@@ -1,19 +1,42 @@
import React, { useState, useEffect } from "react";
-import { fetchGameState } from "../api/game.api";
+import { fetchGameState, submitMove } from "../api/game.api";
+import { convertIndexToPosition } from "../utils/position";
import { Cell } from "../types";
import Board from "./board";
+const DEFAULT_CLICKED_CELL = -1;
+
interface GameProps {
gameId: number;
+ playerId: string;
}
const Game = (props: GameProps) => {
const [isLoading, setLoading] = useState(false);
- const [cellWidth, setCellWidth] = useState(4);
+ const [cellWidth, setCellWidth] = useState(0);
const [cells, setCells] = useState([] as Cell[]);
+ const [focusedCellIndex, setFocusedCellIndex] =
+ useState(DEFAULT_CLICKED_CELL);
+
+ const onCellClicked = (cellIndex: number): void => {
+ if (cellIndex === focusedCellIndex) {
+ setFocusedCellIndex(DEFAULT_CLICKED_CELL);
+ return;
+ } else if (focusedCellIndex === DEFAULT_CLICKED_CELL) {
+ setFocusedCellIndex(cellIndex);
+ return;
+ }
+ submitMove(
+ props.playerId,
+ props.gameId,
+ convertIndexToPosition(focusedCellIndex, cellWidth),
+ convertIndexToPosition(cellIndex, cellWidth)
+ );
+ };
+
useEffect(() => {
setLoading(true);
- fetchGameState("red", props.gameId).then(
+ fetchGameState(props.playerId, props.gameId).then(
({ cells: cellList, cellWidth: width }) => {
setCellWidth(width);
setCells(cellList);
@@ -22,7 +45,14 @@ const Game = (props: GameProps) => {
);
}, [props.gameId]);
- return ;
+ return (
+
+ );
};
export default Game;
diff --git a/ui/package-lock.json b/ui/package-lock.json
index 227dea1..074eedd 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -8,6 +8,7 @@
"name": "ui",
"version": "0.1.0",
"dependencies": {
+ "classnames": "^2.3.1",
"next": "12.1.0",
"react": "17.0.2",
"react-dom": "17.0.2",
@@ -528,6 +529,11 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/classnames": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
+ "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"dev": true,
@@ -2842,6 +2848,11 @@
"supports-color": "^7.1.0"
}
},
+ "classnames": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
+ "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
+ },
"color-convert": {
"version": "2.0.1",
"dev": true,
diff --git a/ui/package.json b/ui/package.json
index fe3cab8..f99fa4f 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -9,6 +9,7 @@
"lint": "next lint"
},
"dependencies": {
+ "classnames": "^2.3.1",
"next": "12.1.0",
"react": "17.0.2",
"react-dom": "17.0.2",
diff --git a/ui/pages/index.tsx b/ui/pages/index.tsx
index 0b16e8e..28a32e3 100644
--- a/ui/pages/index.tsx
+++ b/ui/pages/index.tsx
@@ -11,7 +11,7 @@ const Home: NextPage = () => (
-
+
);
diff --git a/ui/styles/board.module.css b/ui/styles/board.module.css
index ddf1ee2..3fb899c 100644
--- a/ui/styles/board.module.css
+++ b/ui/styles/board.module.css
@@ -5,4 +5,9 @@
.gridCell {
border: 1px solid black;
padding-top: 100%; /* 100% is supposed to be 1:1 aspect ratio but it doesn't look like it */
+ background: 0;
+}
+
+.cellClicked {
+ border: 1px solid red;
}
\ No newline at end of file
diff --git a/ui/types.ts b/ui/types.ts
index 774c563..16036cd 100644
--- a/ui/types.ts
+++ b/ui/types.ts
@@ -3,4 +3,9 @@ export interface Cell {
terrain: boolean;
hidden: boolean;
empty: boolean;
+}
+
+export interface Position {
+ row: number;
+ column: number;
}
\ No newline at end of file
diff --git a/ui/utils/position.ts b/ui/utils/position.ts
new file mode 100644
index 0000000..0361e65
--- /dev/null
+++ b/ui/utils/position.ts
@@ -0,0 +1,9 @@
+import { Position } from "../types";
+
+export const convertIndexToPosition = (
+ index: number,
+ cellWidth: number
+): Position => ({
+ row: Math.floor(index / cellWidth),
+ column: index % cellWidth,
+});