Skip to content
This repository was archived by the owner on May 25, 2021. It is now read-only.
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
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@
"notYourTurn": "Not your turn, please wait for your opponent to play",
"status": "Game Status:",
"created": "Created",
"confirmDelete": "Confirm Delete",
"deleteLabel": "Delete",
"playLabel": "Play",
"yourGames": "Your Games",
"otherGames": "Other Games",
"errorTitle": "Error",
Expand Down
3 changes: 3 additions & 0 deletions generators/app/templates/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@
"notYourTurn": "Not your turn, please wait for your opponent to play",
"status": "Game Status:",
"created": "Created",
"confirmDelete": "Confirm Delete",
"deleteLabel": "Delete",
"playLabel": "Play",
"yourGames": "Your Games",
"otherGames": "Other Games",
"errorTitle": "Error",
Expand Down
3 changes: 3 additions & 0 deletions generators/app/templates/public/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@
"notYourTurn": "No es tu turno, por favor espera a que tu rivla juegue",
"status": "Estado del juego:",
"created": "Creado:",
"confirmDelete": "Confirmar Eliminar",
"deleteLabel": "Eliminar",
"playLabel": "Jugar",
"yourGames": "Tus juegos",
"otherGames": "Otros juegos",
"errorTitle": "Error",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Labeled from './labeled.component';

export default Labeled;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { useState } from 'react';
import styled from 'styled-components';

const Labeled = ({ label, children, component: Component = 'button', ...rest }) => {
const [hover, setHover] = useState(false);

const LComponent = styled(Component)`
position: relative;
& > span.label {
position: absolute;
font-size: 10px;
bottom: 2px;
left: 0;
width: 100%;
text-align: center;
}
`;

return (
<LComponent {...rest} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}>
{children}
<span className="label">{hover && label ? label : ''}</span>
</LComponent>
);
};

export default Labeled;
4 changes: 3 additions & 1 deletion generators/app/templates/src/components/Utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import LanguageDropdown from './LanguageDropdown';
import Toaster from './ToasterNotification/toaster.component';
import Select from './Select';
import ConfirmationDialog from './ConfirmationDialog';
import Labeled from './Labeled';

export {
GradientBackground,
Expand All @@ -25,5 +26,6 @@ export {
Input,
LanguageDropdown,
Toaster,
Select
Select,
Labeled
};
Original file line number Diff line number Diff line change
@@ -1,76 +1,94 @@
import React, { Fragment, useState } from 'react';
import React, { useState, useRef } from 'react';
import moment from 'moment';
import { Link } from 'react-router-dom';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useTranslation } from 'react-i18next';
import { useOnClickOutside } from '@hooks';
import { Labeled } from '@util-components';
import {
Item,
ProfileName,
GameStatus,
Actions,
GameCard,
ProfileImage,
ProfileItems,
DeleteAction
ProfileItems
} from './game-item.style';

type Props = { game: Object, webId: String, deleteGame: Function };

const GameItem = ({ game, webId, deleteGame }: Props) => {
const { status, created, opponent, actor } = game;
const { status, created, opponent, actor, url } = game;
const { t } = useTranslation();
return (
<Item className="card item__span-4-columns">
<GameCard>
<ProfileDisplayItem player={opponent && opponent.webId !== webId ? opponent : actor} />
<GameStatus>{status}</GameStatus>
<ProfileDisplayItem
player={opponent && opponent.webId !== webId ? opponent : actor}
status={status}
created={created}
/>
<Actions>
<GameActions {...{ game, deleteGame }} />
<span>{moment(created).fromNow()}</span>
<DeleteGame deleteGame={deleteGame} game={game} />
<Labeled
to={`tictactoe/${btoa(url)}`}
className="playBtn"
label={t('game.playLabel')}
component={Link}
>
<FontAwesomeIcon icon="play" color="rgb(130, 131, 139)" />
</Labeled>
</Actions>
</GameCard>
</Item>
);
};

const ProfileDisplayItem = ({ player }: { player: String }) => (
<ProfileItems>
{player && <ProfileImage target="_blank" src={player.image} alt="Opponent's profile" />}
{player && <ProfileName href={player.webId}>{player.name}</ProfileName>}
</ProfileItems>
);

const GameActions = ({ game, deleteGame }: { game: Object, deleteGame: Function }) => {
const DeleteGame = ({ game, deleteGame }: { game: Object, deleteGame: Function }) => {
const ref = useRef();
const [deleteMode, setDeleteMode] = useState(false);
const { url } = game;
const { t } = useTranslation();
useOnClickOutside(ref, () => setDeleteMode(false));

return (
<div>
{!deleteMode ? (
<Fragment>
<button type="button" onClick={() => setDeleteMode(true)}>
<FontAwesomeIcon icon="trash-alt" size="2x" color="rgb(239, 89, 80)" />
</button>
{!game.deleted && (
<Link to={`tictactoe/${btoa(url)}`}>
<FontAwesomeIcon icon="play" size="2x" color="rgb(44, 105, 164)" />
</Link>
)}
</Fragment>
<div ref={ref}>
{deleteMode ? (
<button type="button" className="deleteMode" onClick={() => deleteGame(game)}>
<FontAwesomeIcon icon="trash-alt" color="#ffffff" />
<span>{t('game.confirmDelete')}</span>
</button>
) : (
<DeleteAction>
<span> {t('game.deleteConfirmation')}</span>
<div>
<button type="button" onClick={() => deleteGame(game)}>
<FontAwesomeIcon icon="check" size="2x" color="rgb(44, 105, 164)" />
</button>
<button type="button" onClick={() => setDeleteMode(false)}>
<FontAwesomeIcon icon="times" size="2x" color="rgb(239, 89, 80)" />
</button>
</div>
</DeleteAction>
<Labeled
type="button"
label={t('game.deleteLabel')}
className="deleteBtn"
onClick={() => setDeleteMode(true)}
>
<FontAwesomeIcon icon="trash-alt" color="rgb(237, 40, 40)" />
</Labeled>
)}
</div>
);
};

const ProfileDisplayItem = ({
player,
status,
created
}: {
player: String,
status: String,
created: String
}) => (
<ProfileItems>
{player && <ProfileImage target="_blank" src={player.image} alt="Opponent's profile" />}
<div>
{player && <ProfileName href={player.webId}>{player.name}</ProfileName>}
<div>
{status && <span>{status}</span>}
{created && <span className="createdDate">{moment(created).fromNow()}</span>}
</div>
</div>
</ProfileItems>
);

export default GameItem;
Original file line number Diff line number Diff line change
Expand Up @@ -19,51 +19,89 @@ export const GameStatus = styled.span`
flex: 1 1 0;
`;

export const Info = styled.div`
display: flex;
flex-direction: column;

& a {
text-decoration: none;
color: inherit;
font-weight: 700;
letter-spacing: 0.4px;
font-size: 1.2em;
}
`;

export const Actions = styled.div`
display: flex;
flex-direction: column;
align-items: flex-end;
align-items: center;
min-width: 120px;
font-size: 2rem;
justify-content: space-around;
align-items: center;

a {
& > a {
color: inherit;
height: 50px;
width: 50px;
font-size: 1.4rem;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
transition: all 300ms ease-in;
&:hover {
background: rgba(130, 131, 139, 0.1);
}
}

svg {
display: inline-block;
margin: 10px;
}
& > div {
& > button {
&.deleteBtn{
font-size: 1.4rem;
height: 50px;
width: 50px;
border: none;
padding: 0;
position: relative
color: rgba(237, 40, 40, 1);
transition: all 300ms ease-in;
&:hover {
background: rgba(237, 40, 40, 0.1);
}
}

& button {
border: none;
margin: 0;
padding: 0;
&.deleteMode{
width: fit-content;
padding: .8em 1em;
font-size: 1rem;
color: #fff;
background: rgba(237, 40, 40, 1);
outline: none;
border: none;
transition: background 300ms ease-in;
border-radius: 2px;
display: flex;
align-items: center;
& > span {
padding-left: 0.8em;
font-size: 0.7rem;
}
&:hover{
background: rgba(237, 40, 40, 0.9);
}
}

&:hover{
outline: none;
}
}
}
}
`;

export const ProfileImage = styled.img`
width: 75px;
width: 50px;
height: 50px;
border-radius: 50%;
display: inline-block;
vertical-align: middle;
background-size: cover;
overflow: hidden;
visibility: visible;
margin: 0 12px;
`;

export const ProfileName = styled.a`
display: inline-block;
vertical-align: middle;
padding-left: 10px;
text-decoration: none;
color: inherit;
font-weight: 700;
Expand All @@ -74,14 +112,22 @@ export const ProfileName = styled.a`
export const ProfileItems = styled.div`
flex: 1 1 0;
flex-wrap: nowrap;
`;

export const DeleteAction = styled.div`
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;

& > div {
display: flex;
align-items: center;
justify-content: space-between;
flex-direction: column;
& > div {
display: flex;
align-items: center;
& > .createdDate {
padding-left: 1.5em;
color: #ccc;
font-weight: 100;
font-size: 0.9rem;
}
}
}
`;