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

Update countdown component to be generic and fix minor bugs for v0.5.1 #20

Merged
merged 8 commits into from
May 26, 2018
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ $ yarn start
│ │ ...
│ ├── components/ # UI styled-components
│ ├── config/ # config files
│ ├── constants/ # constants (eg. actionType names)
│ ├── constants/ # constants (eg. actionType names, routes)
│ ├── containers/ # game containers
│ │ ├── HomeScreen/
│ │ ├── PlayScreen/
Expand Down
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "marvel-jarvig",
"version": "0.5.0",
"description": "Marvel J.A.R.V.I.G. (Just A Rather Very Interesting Game) is a game that lets you find and discover Marvel Comics characters based on their name, image and description!",
"version": "0.5.1",
"description": "Marvel JARVIG (Just A Rather Very Interesting Game) is a game that lets you find and discover Marvel Comics characters based on their name, image and description!",
"homepage": "https://yassinedoghri.github.io/marvel-jarvig/",
"repository": {
"type": "git",
Expand Down Expand Up @@ -69,6 +69,7 @@
"lint-staged": "^7.0.5",
"prettier": "1.12.1",
"react-test-renderer": "^16.3.2",
"redux-devtools-extension": "^2.13.2",
"stylelint": "^9.2.0",
"stylelint-config-standard": "^18.2.0",
"stylelint-config-styled-components": "^0.1.1",
Expand Down
6 changes: 6 additions & 0 deletions src/actions/GameActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
INIT_NEW_GAME,
NEXT_QUESTION,
PASS_QUESTION,
SAVE_GAME_TIME,
SELECT_CHARACTER,
SET_DIFFICULTY,
UPDATE_SETTINGS
Expand Down Expand Up @@ -59,6 +60,11 @@ export const endGame = () => ({
type: END_GAME
});

export const saveGameTime = time => ({
type: SAVE_GAME_TIME,
payload: time
});

export const callRequest = () => ({
type: API_CALL_REQUEST
});
4 changes: 2 additions & 2 deletions src/components/Logo/__tests__/__snapshots__/index.js.snap
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Logo Block adds mobileIcon modifier 1`] = `
exports[`Logo Block adds mobileicon modifier 1`] = `
<a
className="sc-bxivhb cZFXvN"
href="/"
mobileIcon="true"
mobileicon="true"
onClick={[Function]}
>
<img
Expand Down
4 changes: 2 additions & 2 deletions src/components/Logo/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ describe("Logo Block", () => {
expect(tree).toMatchSnapshot();
});

it("adds mobileIcon modifier", () => {
it("adds mobileicon modifier", () => {
const tree = renderWithTheme(
<MemoryRouter>
<Logo to="/" mobileIcon="true">
<Logo to="/" mobileicon="true">
<Logo.MarvelLogo />
<Logo.JarvigText />
<Logo.Icon />
Expand Down
4 changes: 2 additions & 2 deletions src/components/Logo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ const Logo = styled(Link)`
}

& ${MarvelLogo}, & ${JarvigText} {
display: ${props => (props.mobileIcon ? "none" : "block")};
display: ${props => (props.mobileicon ? "none" : "block")};
}

& ${Icon} {
display: ${props => (props.mobileIcon ? "block" : "none")};
display: ${props => (props.mobileicon ? "block" : "none")};
}

${media.desktop`
Expand Down
1 change: 1 addition & 0 deletions src/constants/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const NEXT_QUESTION = "NEXT_QUESTION";
export const SELECT_CHARACTER = "SELECT_CHARACTER";
export const CLEAR_GAME = "CLEAR_GAME";
export const END_GAME = "END_GAME";
export const SAVE_GAME_TIME = "SAVE_GAME_TIME";

export const API_CALL_REQUEST = "API_CALL_REQUEST";
export const API_CALL_SUCCESS = "API_CALL_SUCCESS";
Expand Down
7 changes: 7 additions & 0 deletions src/constants/routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const Routes = {
Home: "/",
Play: "/play",
Results: "/results"
};

export default Routes;
3 changes: 2 additions & 1 deletion src/containers/App.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { FlexWrapper } from "components";
import Routes from "constants/routes";
import FooterContent from "containers/FooterContent";

import HeaderContent from "containers/HeaderContent";
Expand All @@ -21,7 +22,7 @@ class App extends Component {
<HeaderContent />
<MainContent />
<SidebarHelp />
{location.pathname === "/" && <SidebarSettings />}
{location.pathname === Routes.Home && <SidebarSettings />}
<FooterContent />
</FlexWrapper>
</ThemeProvider>
Expand Down
48 changes: 27 additions & 21 deletions src/containers/Countdown.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { GameUI } from "components";
import PropTypes from "prop-types";
import React, { Component } from "react";

Expand Down Expand Up @@ -28,24 +27,23 @@ class Countdown extends Component {
};
this.timer = 0;
this.startTimer = this.startTimer.bind(this);
this.stopTimer = this.stopTimer.bind(this);
this.countDown = this.countDown.bind(this);
}

componentDidMount() {
const { result, isGamePaused } = this.props;
if (
(result.length === 0 && this.timer === 0) ||
(result.length === 0 && isGamePaused)
) {
this.startTimer();
this.startTimer();
}

componentDidUpdate() {
const { isPaused, onCountdownPaused } = this.props;
if (isPaused) {
onCountdownPaused(this.state.time);
}
}

componentWillUnmount() {
if (this.timer) {
clearInterval(this.timer);
}
this.timer = 0;
this.stopTimer();
}

startTimer() {
Expand All @@ -54,11 +52,18 @@ class Countdown extends Component {
}
}

stopTimer() {
if (this.timer) {
clearInterval(this.timer);
}
this.timer = 0;
}

countDown() {
// Remove one second, set state so a re-render happens.
const { isGamePaused, onCountdownEnd } = this.props;
const { isPaused, onCountdownEnd } = this.props;

if (!isGamePaused) {
if (!isPaused) {
const seconds = this.state.seconds - 1;
this.setState({
time: Countdown.secondsToTime(seconds),
Expand All @@ -67,33 +72,34 @@ class Countdown extends Component {

// Check if we're at zero.
if (seconds === 0) {
clearInterval(this.timer);
onCountdownEnd();
this.stopTimer();
onCountdownEnd(this.state.time);
}
}
}

render() {
const { time } = this.state;
const { isGamePaused } = this.props;
const timer =
time.m === 0
? time.s
: `${time.m}:${time.s < 10 ? `0${time.s}` : time.s}`;

return <GameUI.Label blink={isGamePaused}>{timer}</GameUI.Label>;
return <React.Fragment>{timer}</React.Fragment>;
}
}

Countdown.propTypes = {
from: PropTypes.number.isRequired,
isGamePaused: PropTypes.bool,
result: PropTypes.arrayOf(PropTypes.string).isRequired,
onCountdownEnd: PropTypes.func.isRequired
isPaused: PropTypes.bool,
onCountdownPaused: PropTypes.func,
onCountdownEnd: PropTypes.func
};

Countdown.defaultProps = {
isGamePaused: false
isPaused: false,
onCountdownPaused: () => {},
onCountdownEnd: () => {}
};

export default Countdown;
3 changes: 2 additions & 1 deletion src/containers/FooterContent.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { toggleSidebar } from "actions/UIActions";
import Routes from "constants/routes";
import PropTypes from "prop-types";
import React, { Component } from "react";

Expand All @@ -17,7 +18,7 @@ class FooterContent extends Component {
return (
<Footer>
<Toolbar>
{location.pathname === "/" && (
{location.pathname === Routes.Home && (
<Toolbar.Item md onClick={() => toggleSidebar("settings")}>
<FaCog />
</Toolbar.Item>
Expand Down
55 changes: 39 additions & 16 deletions src/containers/HeaderContent.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,49 @@
import { endGame } from "actions/GameActions";
import { endGame, saveGameTime } from "actions/GameActions";

import { GameUI, Header, Logo } from "components/index";
import Routes from "constants/routes";
import Countdown from "containers/Countdown";
import logo from "containers/MarvelLogo.svg";
import iconJarvig from "containers/icon-jarvig.svg";
import logo from "containers/MarvelLogo.svg";
import PropTypes from "prop-types";
import React, { Component } from "react";
import FaClock from "react-icons/lib/fa/clock-o";

import FaHeart from "react-icons/lib/fa/heart";

import TiChevronLeft from "react-icons/lib/ti/chevron-left";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import { push } from "react-router-redux";
import { bindActionCreators, compose } from "redux";

import TiChevronLeft from "react-icons/lib/ti/chevron-left";
import { formatTimer } from "utils/helpers";

class HeaderContent extends Component {
handleCountdownEnd() {
const { endGame, push } = this.props;
handleCountdownPaused(time) {
const { game, saveGameTime } = this.props;

if (game.time !== time) {
saveGameTime(time);
}
}

handleCountdownEnd(time) {
const { endGame, push, saveGameTime } = this.props;

saveGameTime(time);
endGame();
push("/result");
push(Routes.Results);
}

render() {
const { location, time, game, isLoading, error } = this.props;

const isGamePaused = isLoading || game.checked || game.over || error;

return (
location.pathname !== "/" && (
location.pathname !== Routes.Home && (
<Header>
<Logo inline="true" mobileIcon="true" to="/" title="Go Home">
<Logo inline="true" mobileicon="true" to="/" title="Go Home">
<TiChevronLeft />
<Logo.MarvelLogo sm src={logo} alt="Marvel Logo" />
<Logo.JarvigText sm spaceLeft>
Expand All @@ -43,12 +56,20 @@ class HeaderContent extends Component {
<GameUI.Icon>
<FaClock />
</GameUI.Icon>
<Countdown
from={time * 60}
isGamePaused={isLoading || game.checked || game.over || error}
onCountdownEnd={() => this.handleCountdownEnd()}
result={game.result}
/>
<GameUI.Label blink={isGamePaused}>
{!game.over ? (
<Countdown
from={time * 60}
isPaused={isGamePaused}
onCountdownPaused={time => this.handleCountdownPaused(time)}
onCountdownEnd={time => this.handleCountdownEnd(time)}
/>
) : (
<React.Fragment>
{game.time ? formatTimer(game.time) : 0}
</React.Fragment>
)}
</GameUI.Label>
</GameUI.Item>
<GameUI.Item>
<GameUI.Icon animated>
Expand Down Expand Up @@ -78,6 +99,7 @@ HeaderContent.propTypes = {
message: PropTypes.string
}),
endGame: PropTypes.func.isRequired,
saveGameTime: PropTypes.func.isRequired,
push: PropTypes.func.isRequired
};

Expand All @@ -96,7 +118,8 @@ const mapDispatchToProps = dispatch =>
bindActionCreators(
{
push,
endGame
endGame,
saveGameTime
},
dispatch
);
Expand Down
17 changes: 12 additions & 5 deletions src/containers/MainContent.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import { Main } from "components";
import Routes from "constants/routes";

import HomeScreen from "containers/HomeScreen";
import PlayScreen from "containers/PlayScreen";
import ResultScreen from "containers/ResultScreen";
import PropTypes from "prop-types";
import React, { Component } from "react";
import { Route, Switch, withRouter } from "react-router-dom";
import { Redirect, Route, Switch, withRouter } from "react-router-dom";
import withTracker from "utils/withTracker";

class MainContent extends Component {
render() {
const { location } = this.props;
return (
<Main isHome={location.pathname === "/"}>
<Main isHome={location.pathname === Routes.Home}>
<Switch>
<Route exact path="/" component={withTracker(HomeScreen)} />
<Route path="/play" component={withTracker(PlayScreen)} />
<Route path="/result" component={withTracker(ResultScreen)} />
<Route exact path={Routes.Home} component={withTracker(HomeScreen)} />
<Route exact path={Routes.Play} component={withTracker(PlayScreen)} />
<Route
exact
path={Routes.Results}
component={withTracker(ResultScreen)}
/>
{/* 404: redirects to homepage */}
<Redirect to={Routes.Home} />
</Switch>
</Main>
);
Expand Down
Loading