Skip to content

Commit

Permalink
finish routing for hosting/playing
Browse files Browse the repository at this point in the history
  • Loading branch information
swizzard committed Jul 21, 2020
1 parent 5c831b6 commit 2a8c3d6
Show file tree
Hide file tree
Showing 8 changed files with 333 additions and 215 deletions.
1 change: 1 addition & 0 deletions app/src/DraftDash.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ function Dash({ error, games, match, removeGame, user }) {
selectLabel="Edit Game"
remove={removeGame(g.quizId)}
key={`${user.id}-game-${ix}`}
urlPath="edit"
/>
))
) : (
Expand Down
73 changes: 32 additions & 41 deletions app/src/HostDash.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, { useEffect, useState } from 'react';
import { Route, Switch, useRouteMatch } from 'react-router-dom';
import HostGame from './HostGame';
import { deleteGame, getHostGames } from './db/game';
import { getHostGames } from './db/game';
import HostGameSummary from './HostGameSummary';

export default function HostDash({ setDashState, user }) {
export default function HostDash({ user }) {
const [error, setError] = useState(null);
const [games, setGames] = useState(null);
const [selectedGame, setSelectedGame] = useState(null);
const match = useRouteMatch();

useEffect(() => {
getHostGames(user.id)
Expand All @@ -21,49 +22,39 @@ export default function HostDash({ setDashState, user }) {
.catch((e) => setError(e.message));
}, [user.id]);

function removeGame({ id }) {
return () => {
deleteGame(user.id, id)
.then(() => {
setGames(games.filter((g) => g.id !== id));
})
.catch(() => setError('There was a problem deleting your game'));
};
}
return selectedGame ? (
<HostGame game={selectedGame} user={user} />
) : (
return (
<Switch>
<Route path={`${match.path}/:gameId`}>
<HostGame user={user} />
</Route>
<Route path={`${match.path}`}>
<Dash error={error} games={games} match={match} user={user} />
</Route>
</Switch>
);
}

function Dash({ error, games, user }) {
return (
<>
{error ? (
<div className="row">
<div className="col-sm-12 bg-error">{error}</div>
<div className="bg-error">{error}</div>
</div>
) : null}
<>
{games ? (
games.map((g) => (
<HostGameSummary
key={`${g.quizId}`}
quiz={g}
select={setSelectedGame}
remove={removeGame(g.quizId)}
selectLabel="Host Game"
/>
))
) : (
<h4>No Games</h4>
)}
</>
<div className="row">
<div className="col-sm-12 button-row">
<button
className="btn btn-dark btn-sm"
onClick={() => setDashState(null)}
>
Back
</button>
</div>
</div>
{games && games.length > 0 ? (
games.map((g, ix) => (
<HostGameSummary
quiz={g}
selectLabel="Host Game"
remove={null}
key={`${user.id}-game-${ix}`}
urlPath=""
/>
))
) : (
<h4>No Games</h4>
)}
</>
);
}
94 changes: 64 additions & 30 deletions app/src/HostGame.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,62 @@
import React, { useEffect, useState } from 'react';
import { createHostedGame, getParticipants } from './db/game';
import { useHistory, useRouteMatch } from 'react-router-dom';
import { createHostedGame, getHostGame, getParticipants } from './db/game';
import ScoreGame from './ScoreGame';
import { AuthRedirect } from './Routes';

export default function HostGame({ game, user }) {
export default function HostGame({ user }) {
const [error, setError] = useState(null);
const [participants, setParticipants] = useState([]);
const [currentGame, setCurrentGame] = useState(null);
const [currentRound, setCurrentRound] = useState(0);
const [maxRound, setMaxRound] = useState(0);
const [authorized, setAuthorized] = useState(true);
const [score, setScore] = useState(false);
const history = useHistory();
const match = useRouteMatch();

function goBack() {
history.push('/host');
}

async function getGame() {
const { gameId } = match.params;
const resp = await getHostGame(user.id, gameId);
if (resp.ok) {
return resp.json();
} else if (resp.status === 406) {
setAuthorized(false);
throw new Error('unauthroized');
} else {
throw new Error('There was a problem retrieving your game');
}
}

async function getCode() {
const { gameId } = match.params;
const resp = await createHostedGame(user.id, gameId);
if (resp.ok) {
return resp.json();
} else {
throw new Error('There was an error starting your game');
}
}

async function hostGame() {
try {
const game = await getGame();
const code = await getCode();
game.code = code;
setCurrentGame(game);
setMaxRound(game.quizRounds.length - 1);
} catch (e) {
setError(e.message);
}
}

useEffect(() => {
createHostedGame(user.id, game.quizId)
.then((resp) => {
if (resp.ok) {
return resp.json();
} else {
throw new Error('There was a problem starting your game');
}
})
.then((code) => {
game.code = code;
setCurrentGame(game);
setMaxRound(game.quizRounds.length - 1);
})
.catch((e) => setError(e.message));
}, [game, user.id]);
hostGame();
}, [user.id, match.params.gameId]);

function updateParticipants() {
setError(null);
Expand All @@ -43,9 +74,11 @@ export default function HostGame({ game, user }) {
.catch((e) => setError(e.message));
}

if (score) {
return <ScoreGame code={game.code} />;
} else if (!game) {
if (!authorized) {
return <AuthRedirect />;
} else if (score) {
return <ScoreGame code={currentGame.code} />;
} else if (!currentGame) {
return (
<div className="row">
<div className={`col-sm-12 ${error ? 'bg-error' : ''}`}>
Expand All @@ -63,10 +96,10 @@ export default function HostGame({ game, user }) {
) : null}
<div className="row">
<div className="col-sm-12">
<h4>{game.quizName}</h4>
<h4>{currentGame.quizName}</h4>
</div>
</div>
<CopyCodeButton code={game.code} />
<CopyCodeButton code={currentGame.code} />
<div className="row">
<div className="col-sm-12">
<div className="card">
Expand Down Expand Up @@ -95,9 +128,9 @@ export default function HostGame({ game, user }) {
<div className="row">
<div className="col-sm-12">
<Round
key={`game-${game.quizId}-round-${currentRound}`}
key={`game-${currentGame.quizId}-round-${currentRound}`}
roundNo={currentRound}
questions={game.quizRounds[currentRound].questions}
questions={currentGame.quizRounds[currentRound].questions}
/>
</div>
</div>
Expand Down Expand Up @@ -186,29 +219,30 @@ function HostQuestion({ question, answers, ix }) {
function CopyCodeButton({ code }) {
const [copied, setCopied] = useState(false);
const [err, setErr] = useState(false);
const copyCode = () =>
const link = `${window.location.origin}/play/${code}`;
const copyLink = () =>
navigator.clipboard
.writeText(code)
.writeText(link)
.then(() => setCopied(true))
.catch(() => setErr(true));
return (
<div className="card">
<div className="card-body">
<h5 className="card-title">Code: {code}</h5>
<h5 className="card-title">Link: {link}</h5>
<h6 className="card-subtitle">
Send this code to your players so they can join the game!
Send this link to your players so they can join the game!
</h6>
</div>
<div className="card-body">
{!copied && !err ? (
<button className="btn btn-dark" type="button" onClick={copyCode}>
<button className="btn btn-dark" type="button" onClick={copyLink}>
Copy
</button>
) : copied ? (
<span className="small">Copied!</span>
) : (
<span className="bg-danger">
An error occurred&mdash;please copy the code manually.
An error occurred&mdash;please copy the link manually.
</span>
)}
</div>
Expand Down
19 changes: 14 additions & 5 deletions app/src/HostGameSummary.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ function countQuestions(game) {
game.quizRounds.forEach((r) => (numQs += r.questions.length));
return numQs;
}
export default function HostGameSummary({ quiz, remove, selectLabel }) {
export default function HostGameSummary({
quiz,
remove,
selectLabel,
urlPath
}) {
const match = useRouteMatch();
return (
<>
Expand All @@ -27,13 +32,17 @@ export default function HostGameSummary({ quiz, remove, selectLabel }) {
<div className="col-sm-12 btn-group">
<Link
className="btn btn-dark"
to={`${match.path}/edit/${quiz.quizId}`}
to={`${match.path}${urlPath ? `/${urlPath}` : ''}/${quiz.quizId}`}
>
{selectLabel}
</Link>
<button className="btn btn-dark" onClick={remove}>
Delete
</button>
{remove ? (
<button className="btn btn-dark" onClick={remove}>
Delete
</button>
) : (
''
)}
</div>
</div>
</>
Expand Down
5 changes: 0 additions & 5 deletions app/src/Nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ export default function Nav({ user, setUser }) {
Host a Game
</Link>
</li>
<li className="nav-item">
<Link className="btn btn-dark" to="/play">
Play a Game
</Link>
</li>
<li className="nav-item">
<button
className="btn btn-dark"
Expand Down
79 changes: 10 additions & 69 deletions app/src/PlayDash.js
Original file line number Diff line number Diff line change
@@ -1,73 +1,14 @@
import React, { useState } from 'react';
import React from 'react';
import { Route, Switch, useRouteMatch } from 'react-router-dom';
import PlayerGame from './PlayerGame';
import { joinGame } from './db/game';

export default function PlayDash({ setDashState, user }) {
const [participantId, setParticipantId] = useState(null);
const [gameCode, setGameCode] = useState(null);
const [game, setGame] = useState(null);
const [error, setError] = useState(null);

function loadGame() {
if (gameCode) {
joinGame(user.id, gameCode)
.then((resp) => {
if (resp.ok) {
return resp.json();
} else {
throw new Error('There was an error loading your game');
}
})
.then(([{ participantId: pId, game }]) => {
setGame(game.quiz);
setParticipantId(pId);
})
.catch((e) => setError(e.message));
} else {
setError('Missing game code');
}
}

return game ? (
<PlayerGame
game={game}
key={`${gameCode}-${participantId}`}
participantId={participantId}
/>
) : (
<>
{error ? <div className="bg-danger">{error}</div> : null}
<form>
<div className="form-group">
<label>Game Code</label>
<input
className="form-control"
type="text"
onChange={(e) => {
setError(null);
setGameCode(e.target.value);
}}
/>
</div>
<div>
<button
className="btn btn-dark"
type="button"
onClick={() => loadGame()}
>
Play
</button>
</div>
</form>
<div>
<button
className="btn btn-dark btn-sm"
type="button"
onClick={() => setDashState(null)}
>
Back
</button>
</div>
</>
export default function PlayDash({ user }) {
const match = useRouteMatch();
return (
<Switch>
<Route path={`${match.path}/:gameCode`}>
<PlayerGame user={user} />
</Route>
</Switch>
);
}
Loading

0 comments on commit 2a8c3d6

Please sign in to comment.