Skip to content

Commit

Permalink
Show played and not played cards for all players
Browse files Browse the repository at this point in the history
- Add card placeholder, hidden and disabled state
- Move FETCH_PROFILE query to App.js
- Show played and not played cards for all players, show current player turn
  • Loading branch information
arielger committed Mar 17, 2019
1 parent 1bd1ca6 commit 9749fa9
Show file tree
Hide file tree
Showing 14 changed files with 336 additions and 109 deletions.
1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"apollo-link-http": "^1.5.11",
"apollo-link-ws": "^1.0.14",
"apollo-utilities": "^1.2.1",
"classnames": "^2.2.6",
"formik": "^1.5.1",
"graphql": "^14.1.1",
"node-sass": "^4.11.0",
Expand Down
40 changes: 33 additions & 7 deletions client/src/App.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { Fragment } from "react";
import * as R from "ramda";
import { ApolloProvider, Query } from "react-apollo";
import { ApolloClient } from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
Expand All @@ -14,6 +15,7 @@ import ReactModal from "react-modal";

import { Login, Matches, Match } from "./screens";
import Header from "./components/Header";
import styles from "./App.module.scss";

ReactModal.setAppElement("#root");

Expand Down Expand Up @@ -76,6 +78,16 @@ const IS_LOGGED_IN = gql`
}
`;

const FETCH_PROFILE = gql`
{
me {
id
avatar
name
}
}
`;

const App = () => {
return (
<div id="main">
Expand All @@ -85,13 +97,27 @@ const App = () => {
<Fragment>
<BrowserRouter>
{isLoggedIn ? (
<div>
<Header client={client} />
<Switch>
<Route path="/matches" component={Matches} />
<Route path="/match/:matchId" component={Match} />
<Redirect to="/matches" />
</Switch>
<div className={styles["layout"]}>
<Query query={FETCH_PROFILE}>
{({ data, loading, error }) => {
const user = R.prop("me", data);
return (
<>
<Header client={client} user={user} />
<Switch>
<Route path="/matches" component={Matches} />
<Route
path="/match/:matchId"
render={({ ...props }) => (
<Match user={user} {...props} />
)}
/>
<Redirect to="/matches" />
</Switch>
</>
);
}}
</Query>
</div>
) : (
<Switch>
Expand Down
5 changes: 5 additions & 0 deletions client/src/App.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.layout {
display: flex;
flex-direction: column;
height: 100vh;
}
62 changes: 53 additions & 9 deletions client/src/components/Card/Card.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,68 @@
import React from "react";
import cs from "classnames";

import styles from "./Card.module.scss";

const cardSize = {
width: 117,
height: 180
};

const stepCardYOffset = {
GOLD: "0",
CUP: "-319px",
SWORD: "-638px",
BASTO: "-958px"
GOLD: 0,
CUP: 1,
SWORD: 2,
BASTO: 3
};

export default function Card({ card, onClick }) {
export default function Card({
isPlaceholder,
isHidden,
isDisabled,
card,
onClick
}) {
if (isHidden || isPlaceholder) {
return (
<div
className={styles.card}
style={{
...cardSize,
...(isHidden
? {
backgroundPosition: `${-1 * cardSize.width}px ${-4 *
cardSize.height}px`
}
: {}),
...(isPlaceholder
? {
border: "1px dashed white",
background: "none",
width: cardSize.width - 2
}
: {})
}}
/>
);
}

const [cardNumber, cardStep] = card.split("-");

return (
<div
onClick={() => onClick(card)}
className={styles["card"]}
className={cs({
[styles.card]: true,
[styles.disabled]: isDisabled
})}
style={{
backgroundPosition: `${(cardNumber - 1) * -208}px ${
stepCardYOffset[cardStep]
}`
...cardSize,
cursor: onClick ? "pointer" : "initial",
backgroundPosition: isHidden
? `${-1 * cardSize.width}px ${-4 * cardSize.height}px`
: `${(cardNumber - 1) * -cardSize.width}px ${-stepCardYOffset[
cardStep
] * cardSize.height}px`
}}
/>
);
Expand Down
9 changes: 6 additions & 3 deletions client/src/components/Card/Card.module.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
.card {
width: 208px;
height: 319px;
background-color: white;
border-radius: 16px;
border-radius: 12px;
background-image: url("./cards.png");
background-size: 1404px;
margin: 0 12px;

&.disabled {
opacity: 0.5;
}
}
27 changes: 3 additions & 24 deletions client/src/components/Header/Header.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,15 @@
import React from "react";
import * as R from "ramda";
import { Query } from "react-apollo";
import gql from "graphql-tag";

import styles from "./Header.module.scss";

const FETCH_PROFILE = gql`
{
me {
avatar
name
}
}
`;

export default function Header({ client }) {
export default function Header({ client, user }) {
return (
<div className={styles["header"]}>
<h2 className={styles["title"]}>Truco</h2>
<div className={styles["right-container"]}>
<Query query={FETCH_PROFILE}>
{({ data, loading, error }) => (
<>
<h4>{R.path(["me", "name"], data)}</h4>
<img
className={styles["avatar"]}
src={R.path(["me", "avatar"], data)}
alt=""
/>
</>
)}
</Query>
<h4>{R.prop("name", user)}</h4>
<img className={styles["avatar"]} src={R.prop("avatar", user)} alt="" />
<button
onClick={() => {
localStorage.removeItem("token");
Expand Down
92 changes: 62 additions & 30 deletions client/src/screens/Match/Match.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React from "react";
import React, { Fragment } from "react";
import * as R from "ramda";
import { Query, Mutation } from "react-apollo";
import { Prompt } from "react-router-dom";
import gql from "graphql-tag";

import styles from "./Match.module.scss";
import Card from "../../components/Card";
import PlayerCards from "./PlayerCards";

const matchFields = `
status
Expand All @@ -25,6 +25,11 @@ const matchFields = `
card
played
}
cardsPlayedByPlayer {
playerId
cards
}
nextPlayer
`;

const MATCH_QUERY = gql`
Expand All @@ -47,13 +52,27 @@ const MATCH_SUBSCRIPTION = gql`
const PLAY_CARD = gql`
mutation playCard($matchId: ID!, $cardId: ID!) {
playCard(matchId: $matchId, cardId: $cardId) {
card
played
myCards {
id
card
played
}
cardsPlayedByPlayer {
playerId
cards
}
}
}
`;

const MatchInner = ({ matchId, subscribeToUpdates, data, loading, error }) => {
const MatchInner = ({
user,
matchId,
subscribeToUpdates,
data,
loading,
error
}) => {
React.useEffect(() => {
const unsubscribe = subscribeToUpdates();
return () => {
Expand All @@ -64,8 +83,16 @@ const MatchInner = ({ matchId, subscribeToUpdates, data, loading, error }) => {
if (loading) return <span>Loading</span>;
if (error) return <span>Error</span>;

const notPlayedCards = R.reject(R.prop("played"), data.match.myCards);
const playedCards = R.pipe(
R.find(R.propEq("playerId", user.id)),
R.prop("cards")
)(data.match.cardsPlayedByPlayer);

const otherPlayers = R.reject(R.propEq("id", user.id), data.match.players);

return (
<div>
<div className={styles["match-inner"]}>
{data.match.status === "waiting" && (
<div className={styles["waiting-container"]}>
<h1>Partida de {data.match.creator.name}</h1>
Expand All @@ -88,38 +115,45 @@ const MatchInner = ({ matchId, subscribeToUpdates, data, loading, error }) => {
</div>
)}
{data.match.status === "playing" && (
<div>
<div className={styles["cards"]}>
<Mutation mutation={PLAY_CARD}>
{playCard =>
R.reject(R.prop("played"))(data.match.myCards).map(
({ id: cardId, card }) => (
<Card
onClick={() =>
playCard({ variables: { matchId, cardId } })
}
card={card}
/>
)
)
}
</Mutation>
</div>
</div>
<Fragment>
{otherPlayers.map(player => (
<PlayerCards
position="top" //@todo: Refactor to handle 4 and 6 players
playedCards={R.pipe(
R.find(R.propEq("playerId", player.id)),
R.prop("cards")
)(data.match.cardsPlayedByPlayer)}
/>
))}
<Mutation mutation={PLAY_CARD}>
{playCard => (
<PlayerCards
position="bottom"
isCurrentUser={true}
isYourTurn={data.match.nextPlayer === user.id}
playedCards={playedCards}
notPlayedCards={notPlayedCards}
handlePlayCard={cardId =>
playCard({ variables: { matchId, cardId } })
}
/>
)}
</Mutation>
</Fragment>
)}
</div>
);
};

export default function Match({ match }) {
export default function Match({ user, match }) {
const matchId = match.params.matchId;

React.useEffect(() => {
// @todo: Join match when entering Match screen (so it's possible to share URL)
}, []);

return (
<div>
<div className={styles["match"]}>
<Prompt message="Estas seguro que quieres abandonar la partida?" />
<Query
query={MATCH_QUERY}
Expand All @@ -129,6 +163,7 @@ export default function Match({ match }) {
{({ subscribeToMore, ...result }) => (
<MatchInner
{...result}
user={user}
matchId={matchId}
subscribeToUpdates={() =>
subscribeToMore({
Expand All @@ -141,10 +176,7 @@ export default function Match({ match }) {
data: { matchUpdated }
}
}
) => {
console.log("matchUpdated:", matchUpdated);
return { ...prev, match: matchUpdated };
}
) => ({ ...prev, match: matchUpdated })
})
}
/>
Expand Down
9 changes: 7 additions & 2 deletions client/src/screens/Match/Match.module.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.match {
flex-grow: 1;
}

.waiting-container {
display: flex;
flex-direction: column;
Expand All @@ -17,6 +21,7 @@
margin: 0 16px;
}

.cards {
display: flex;
.match-inner {
position: relative;
height: 100%;
}
Loading

0 comments on commit 9749fa9

Please sign in to comment.