Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore() - Major refactor of redux state + model #341

Merged
merged 4 commits into from
Feb 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cypress/integration/finding-nora.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// TODO: First find a way to mock randomness to enable e2e tests
describe("Basic Happy flows", function() {
it("Should render a grid with letter N O R A in it", function() {
cy.visit("http://localhost:3000/");

cy.get(".grid").contains("N");
cy.get(".grid").contains("O");
cy.get(".grid").contains("R");
cy.get(".grid").contains("A");
});
});
74 changes: 0 additions & 74 deletions cypress/integration/finding-words.e2e.js

This file was deleted.

19 changes: 10 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@
"coveralls": "yarn test --coverage && cat ./coverage/lcov.info | coveralls"
},
"devDependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/jest-dom": "^5.1.0",
"@testing-library/react": "^9.4.0",
"@types/classnames": "^2.2.8",
"@types/howler": "^2.1.2",
"@types/jest": "^24.0.25",
"@types/node": "^13.1.4",
"@types/jest": "^25.1.1",
"@types/node": "^13.7.0",
"@types/reach__router": "^1.2.6",
"@types/react": "^16.9.17",
"@types/react-dom": "^16.9.4",
"@types/react-redux": "^7.1.5",
"@types/react": "^16.9.19",
"@types/react-dom": "^16.9.5",
"@types/react-redux": "^7.1.7",
"coveralls": "^3.0.9",
"cypress": "^3.8.1",
"cypress": "^3.8.3",
"global": "^4.4.0",
"react-scripts": "^3.3.0",
"typescript": "^3.7.4"
"react-scripts": "^3.3.1",
"typescript": "^3.7.5"
},
"dependencies": {
"@bugsnag/js": "^6.5.0",
Expand All @@ -38,6 +38,7 @@
"@fortawesome/react-fontawesome": "^0.1.8",
"classnames": "^2.2.6",
"howler": "^2.1.3",
"immer": "^5.3.2",
"minimal-analytics": "^0.1.15",
"prevent-double-tap-zoom": "^2.0.4",
"react": "^16.12.0",
Expand Down
122 changes: 69 additions & 53 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,81 @@
import { faCog, faInfoCircle, faRedo } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as React from "react";

import React, { useState } from "react";
import {
useSelector as useReduxSelector,
TypedUseSelectorHook,
useDispatch
} from "react-redux";
import Grid from "./components/Grid";
import AboutPage from "./pages/About";
import NewGamePage from "./pages/NewGame";
import SettingsPage from "./pages/Settings";

import BackgroundImage from "./components/BackgroundImage";
import BottomBar from "./components/BottomBar";
import Button from "./components/Button";
import Overlay from "./components/Overlay";
import { IGridItem, StatusEnum } from "./types";
import { AppState } from "./redux/reducers";
import { AppDispatch } from "./";
import { filterPossibleSolutions } from "model/puzzle";
import {
youWon,
addCorrect,
addAlmost,
addWrong,
updateSolution,
restart
} from "redux/actions";
import "./App.css";
import { GridType, IGameState, IGridItem, StatusEnum } from "./types";

export const useSelector: TypedUseSelectorHook<AppState> = useReduxSelector;

const festenUrl =
"https://res.cloudinary.com/vnglst/image/upload/f_auto/v1537882150/festen.jpg";

interface IAddAnswer {
answer: IGridItem;
solution: string[];
grid: GridType;
}
interface IAppProps {
didWin: boolean;
didLoose: boolean;
remainingSolution: string[];
solution: string[];
updateSolution: (solution: string[]) => void;
restart: () => void;
game: IGameState;
addAnswer: ({ answer, solution, grid }: IAddAnswer) => void;
}
export default function App() {
const [page, setPage] = useState("home");
const dispatch: AppDispatch = useDispatch();
const grid = useSelector(state => state.grid);
const remaining = useSelector(state => state.remaining);
const solution = useSelector(state => state.solution);
const solutions = useSelector(state => state.solutions);
const didWin = useSelector(state => state.remaining.length === 0);

export default function App({
didWin,
didLoose,
updateSolution,
restart,
solution,
remainingSolution,
game,
addAnswer
}: IAppProps) {
const [page, setPage] = React.useState("home");
function handleClick(answer: IGridItem) {
if (answer.status === StatusEnum.Correct) return;

const possibleSolutions = filterPossibleSolutions(solutions, answer);

if (possibleSolutions.length > 0) {
dispatch(addCorrect(answer));
if (remaining.length <= 1) dispatch(youWon());
return;
}

const almostCorrect = solutions.find(solution => {
return solution.find(
s => s.column === answer.column && s.row === answer.row
);
});

const handleClick = (item: IGridItem) => {
if (
item.status === StatusEnum.Correct ||
item.status === StatusEnum.Wrong
) {
return; // already answered
if (almostCorrect) {
dispatch(addAlmost(answer));
return;
}
addAnswer({ answer: item, solution: game.solution, grid: game.grid });
};

dispatch(addWrong(answer));
}

return (
<BackgroundImage imageSrc={festenUrl}>
<div className="app">
<h1>{remainingSolution}</h1>
<h1>{remaining}</h1>
<Grid>
{game.grid.map((row, rowIndex) =>
row.map((item, columnIndex) => (
{grid.map((_, row) =>
_.map((item, column) => (
<Grid.Item
key={`${rowIndex}-${columnIndex}`}
key={`${row}-${column}`}
onClick={() => handleClick(item)}
falldown={item.status === StatusEnum.Wrong}
red={item.status === StatusEnum.Wrong}
Expand Down Expand Up @@ -93,13 +105,18 @@ export default function App({
/>
</BottomBar>
{page === "new-game" && (
<NewGamePage onNavigate={setPage} restart={restart} />
<NewGamePage
onNavigate={setPage}
restart={() => dispatch(restart())}
/>
)}
{page === "settings" && (
<SettingsPage
solution={solution}
updateSolution={updateSolution}
restart={restart}
updateSolution={newSolution =>
dispatch(updateSolution(newSolution))
}
restart={() => dispatch(restart())}
onNavigate={setPage}
/>
)}
Expand All @@ -113,14 +130,13 @@ export default function App({
{didWin && page === "home" && (
<Overlay>
<p>YOU WON</p>
<Button onMouseDown={restart}>Play again?</Button>
</Overlay>
)}

{didLoose && page === "home" && (
<Overlay>
<p>YOU LOST</p>
<Button onMouseDown={restart}>Play again?</Button>
<Button
onMouseDown={() => {
dispatch(restart());
}}
>
Play again?
</Button>
</Overlay>
)}
</div>
Expand Down
65 changes: 0 additions & 65 deletions src/AppContainer.tsx

This file was deleted.

Loading