diff --git a/frontend/components/App.test.js b/frontend/components/App.test.js index 96965c559..bbbd28a53 100644 --- a/frontend/components/App.test.js +++ b/frontend/components/App.test.js @@ -1,4 +1,17 @@ // Write your tests here +import React from "react" +import { render, screen, waitFor } from '@testing-library/react'; + +import AppClass from "./AppClass"; +import AppFunctional from "./AppFunctional" + test('sanity', () => { - expect(true).toBe(false) + expect(true).toBe(true) }) +test('render AppClass without errors', () => { + render(); +}); + +test('render AppFunctional without errors', () => { + render(); +}); diff --git a/frontend/components/AppClass.js b/frontend/components/AppClass.js index 5b964060a..d016cc645 100644 --- a/frontend/components/AppClass.js +++ b/frontend/components/AppClass.js @@ -1,4 +1,5 @@ import React from 'react' +import axios from "axios" // Suggested initial states const initialMessage = '' @@ -16,70 +17,215 @@ const initialState = { export default class AppClass extends React.Component { // THE FOLLOWING HELPERS ARE JUST RECOMMENDATIONS. // You can delete them and build your own logic from scratch. + constructor(){ + super(); - getXY = () => { + this.state = { + gameState: { + ...initialState, + xCoord: 2, + yCoord: 2 + } + } + } + + getXY = (coordinate, x, y) => { // It it not necessary to have a state to track the coordinates. // It's enough to know what index the "B" is at, to be able to calculate them. + if (coordinate === "11"){ + this.move(0, x, y) + } + else if (coordinate === "21"){ + this.move(1, x, y) + } + else if (coordinate === "31"){ + this.move(2, x, y) + } + else if (coordinate === "12"){ + this.move(3, x, y) + } + else if (coordinate === "22"){ + this.move(4, x, y) + } + else if (coordinate === "32"){ + this.move(5, x, y) + } + else if (coordinate === "13"){ + this.move(6, x, y) + } + else if (coordinate === "23"){ + this.move(7, x, y) + } + else if (coordinate === "33"){ + this.move(8, x, y) + } } - getXYMessage = () => { + getXYMessage = (direction) => { // It it not necessary to have a state to track the "Coordinates (2, 2)" message for the user. // You can use the `getXY` helper above to obtain the coordinates, and then `getXYMessage` // returns the fully constructed string. + + if (direction === "left"){ + this.setState({ + ...this.state, gameState: { + ...this.state.gameState, + message: "You can't go left" + } + }) + } + else if (direction === "right"){ + this.setState({ + ...this.state, gameState: { + ...this.state.gameState, + message: "You can't go right" + } + }) + } + else if (direction === "up"){ + this.setState({ + ...this.state, gameState: { + ...this.state.gameState, + message: "You can't go up" + } + }) + } + else if (direction === "down"){ + this.setState({ + ...this.state, gameState: { + ...this.state.gameState, + message: "You can't go down" + } + }) + } } reset = () => { // Use this helper to reset all states to their initial values. + this.setState({ + ...this.state, + gameState: { + message: initialState.message, + email: initialState.email, + index: initialState.index, + steps: initialState.steps, + xCoord: 2, + yCoord: 2 + } + }) } getNextIndex = (direction) => { // This helper takes a direction ("left", "up", etc) and calculates what the next index // of the "B" would be. If the move is impossible because we are at the edge of the grid, // this helper should return the current index unchanged. + + if (direction === "left" && this.state.gameState.xCoord !== 1){ + const newXCoord = this.state.gameState.xCoord - 1; + const newYCoord = this.state.gameState.yCoord; + this.getXY(("" + newXCoord + newYCoord), newXCoord, newYCoord); + } + else if (direction === "right" && this.state.gameState.xCoord !== 3){ + const newXCoord = this.state.gameState.xCoord + 1; + const newYCoord = this.state.gameState.yCoord; + this.getXY(("" + newXCoord + newYCoord), newXCoord, newYCoord); + } + else if (direction === "up" && this.state.gameState.yCoord !== 1){ + const newXCoord = this.state.gameState.xCoord; + const newYCoord = this.state.gameState.yCoord - 1; + this.getXY(("" + newXCoord + newYCoord), newXCoord, newYCoord); + } + else if (direction === "down" && this.state.gameState.yCoord !== 3){ + const newXCoord = this.state.gameState.xCoord; + const newYCoord = this.state.gameState.yCoord + 1; + this.getXY(("" + newXCoord + newYCoord), newXCoord, newYCoord); + } + else { + this.getXYMessage(direction); + } } - move = (evt) => { + move = (newIndex, x, y) => { // This event handler can use the helper above to obtain a new index for the "B", // and change any states accordingly. + this.setState({ + ...this.state, + gameState: { + ...this.state.gameState, + index: newIndex, + xCoord: x, + yCoord: y, + steps: this.state.gameState.steps + 1, + message: "" + } + }) } onChange = (evt) => { - // You will need this to update the value of the input. + const emailInput = evt.target.value; + this.setState({ + ...this.state, gameState: { + ...this.state.gameState, + email: emailInput + } + }) } - onSubmit = (evt) => { - // Use a POST request to send a payload to the server. + onSubmit = (evt) => { + evt.preventDefault(); + const URL = "http://localhost:9000/api/result" + axios.post(URL, {"x": this.state.gameState.xCoord, "y": this.state.gameState.yCoord, "steps": this.state.gameState.steps, "email": this.state.gameState.email}) + .then(res => { + this.setState({ + ...this.state, + gameState: { + ...this.state.gameState, + message: res.data.message, + email: "" + } + }) + }) + .catch(err => { + this.setState({ + ...this.state, + gameState: { + ...this.state.gameState, + message: err.response.data.message + } + }) + }); } render() { + const { className } = this.props return (
-

Coordinates (2, 2)

-

You moved 0 times

+

Coordinates ({this.state.gameState.xCoord}, {this.state.gameState.yCoord})

+

You moved {this.state.gameState.steps} {this.state.gameState.steps === 1 ? "time" : "times"}

{ [0, 1, 2, 3, 4, 5, 6, 7, 8].map(idx => ( -
- {idx === 4 ? 'B' : null} +
+ {idx === this.state.gameState.index ? 'B' : null}
)) }
-

+

{this.state.gameState.message}

- - - - - + + + + +
-
- + +
diff --git a/frontend/components/AppFunctional.js b/frontend/components/AppFunctional.js index 4c2b53a98..82b9fc3ab 100644 --- a/frontend/components/AppFunctional.js +++ b/frontend/components/AppFunctional.js @@ -1,5 +1,5 @@ -import React from 'react' - +import React, { useState } from 'react' +import axios from "axios" // Suggested initial states const initialMessage = '' const initialEmail = '' @@ -10,67 +10,187 @@ export default function AppFunctional(props) { // THE FOLLOWING HELPERS ARE JUST RECOMMENDATIONS. // You can delete them and build your own logic from scratch. - function getXY() { + function getXY(coordinate, x, y) { // It it not necessary to have a state to track the coordinates. // It's enough to know what index the "B" is at, to be able to calculate them. + if (coordinate === "11"){ + move(0, x, y) + } + else if (coordinate === "21"){ + move(1, x, y) + } + else if (coordinate === "31"){ + move(2, x, y) + } + else if (coordinate === "12"){ + move(3, x, y) + } + else if (coordinate === "22"){ + move(4, x, y) + } + else if (coordinate === "32"){ + move(5, x, y) + } + else if (coordinate === "13"){ + move(6, x, y) + } + else if (coordinate === "23"){ + move(7, x, y) + } + else if (coordinate === "33"){ + move(8, x, y) + } } - function getXYMessage() { + function getXYMessage(direction) { // It it not necessary to have a state to track the "Coordinates (2, 2)" message for the user. // You can use the `getXY` helper above to obtain the coordinates, and then `getXYMessage` // returns the fully constructed string. + if (direction === "left"){ + setGameState({ + ...gameState, + message: "You can't go left" + }) + } + else if (direction === "right"){ + setGameState({ + ...gameState, + message: "You can't go right" + }) + } + else if (direction === "up"){ + setGameState({ + ...gameState, + message: "You can't go up" + }) + } + else if (direction === "down"){ + setGameState({ + ...gameState, + message: "You can't go down" + }) + } } function reset() { // Use this helper to reset all states to their initial values. + setGameState({ + message: initialMessage, + email: initialEmail, + index: initialIndex, + steps: initialSteps, + xCoord: 2, + yCoord: 2 + }); } function getNextIndex(direction) { // This helper takes a direction ("left", "up", etc) and calculates what the next index // of the "B" would be. If the move is impossible because we are at the edge of the grid, // this helper should return the current index unchanged. + if (direction === "left" && gameState.xCoord !== 1){ + const newXCoord = gameState.xCoord - 1; + const newYCoord = gameState.yCoord; + getXY(("" + newXCoord + newYCoord), newXCoord, newYCoord); + } + else if (direction === "right" && gameState.xCoord !== 3){ + const newXCoord = gameState.xCoord + 1; + const newYCoord = gameState.yCoord; + getXY(("" + newXCoord + newYCoord), newXCoord, newYCoord); + } + else if (direction === "up" && gameState.yCoord !== 1){ + const newXCoord = gameState.xCoord; + const newYCoord = gameState.yCoord - 1; + getXY(("" + newXCoord + newYCoord), newXCoord, newYCoord); + } + else if (direction === "down" && gameState.yCoord !== 3){ + const newXCoord = gameState.xCoord; + const newYCoord = gameState.yCoord + 1; + getXY(("" + newXCoord + newYCoord), newXCoord, newYCoord); + } + else { + getXYMessage(direction); + } } - function move(evt) { + function move(newIndex, x, y) { // This event handler can use the helper above to obtain a new index for the "B", // and change any states accordingly. + setGameState({ + ...gameState, + index: newIndex, + steps: gameState.steps + 1, + xCoord: x, + yCoord: y, + message: "" + }) } function onChange(evt) { // You will need this to update the value of the input. + const emailInput = evt.target.value; + setGameState({ + ...gameState, + email: emailInput + }) } function onSubmit(evt) { // Use a POST request to send a payload to the server. + evt.preventDefault(); + const URL = "http://localhost:9000/api/result"; + axios.post(URL, {"x": gameState.xCoord, "y": gameState.yCoord, "steps": gameState.steps, "email": gameState.email}) + .then(res => { + setGameState({ + ...gameState, + message: res.data.message, + email: "" + }) + }) + .catch(err => { + setGameState({ + ...gameState, + message: err.response.data.message + }) + }) } + const [gameState, setGameState] = useState({ + message: initialMessage, + email: initialEmail, + index: initialIndex, + steps: initialSteps, + xCoord: 2, + yCoord: 2 + }) + return (
-

Coordinates (2, 2)

-

You moved 0 times

+

Coordinates ({gameState.xCoord}, {gameState.yCoord})

+

You moved {gameState.steps} {gameState.steps === 1 ? "time" : "times"}

{ [0, 1, 2, 3, 4, 5, 6, 7, 8].map(idx => ( -
- {idx === 4 ? 'B' : null} +
+ {idx === gameState.index ? 'B' : null}
)) }
-

+

{gameState.message}

- - - - - + + + + +
-
- + +
diff --git a/package-lock.json b/package-lock.json index c89fb7758..01d90154b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12564,7 +12564,8 @@ "node_modules/react-is": { "version": "18.1.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==" + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true }, "node_modules/react-router": { "version": "6.3.0", @@ -18073,8 +18074,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", - "dev": true, - "requires": {} + "dev": true }, "@webpack-cli/info": { "version": "1.4.1", @@ -18089,8 +18089,7 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", - "dev": true, - "requires": {} + "dev": true }, "@xmldom/xmldom": { "version": "0.7.5", @@ -18159,15 +18158,13 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "requires": {} + "dev": true }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-walk": { "version": "7.2.0", @@ -18239,8 +18236,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} + "dev": true }, "ansi-align": { "version": "3.0.1", @@ -21279,8 +21275,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "requires": {} + "dev": true }, "ieee754": { "version": "1.2.1", @@ -22647,8 +22642,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "28.0.2", @@ -24478,8 +24472,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "requires": {} + "dev": true }, "postcss-modules-local-by-default": { "version": "4.0.0", @@ -24766,7 +24759,8 @@ "react-is": { "version": "18.1.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==" + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true }, "react-router": { "version": "6.3.0", @@ -25735,8 +25729,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", - "dev": true, - "requires": {} + "dev": true }, "styled-components": { "version": "5.3.5", @@ -26810,8 +26803,7 @@ "version": "8.7.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.7.0.tgz", "integrity": "sha512-c2gsP0PRwcLFzUiA8Mkr37/MI7ilIlHQxaEAtd0uNMbVMoy8puJyafRlm0bV9MbGSabUPeLrRRaqIBcFcA2Pqg==", - "dev": true, - "requires": {} + "dev": true }, "xdg-basedir": { "version": "4.0.0",