Skip to content
This repository was archived by the owner on Dec 22, 2022. It is now read-only.

Commit

Permalink
refactor: simplify types
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathanWbn committed Jun 29, 2022
1 parent 888034a commit 9d95310
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 87 deletions.
8 changes: 4 additions & 4 deletions components/game-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { MouseEvent, useContext, useState } from "react";
import axios from "axios";

import { DataContext } from "../pages";
import { Game, Team } from "../domain/Game";
import { Team } from "../domain/Game";
import Image from "next/image";
import { PlayerId } from "../domain/Player";
import { uniq } from "lodash";
Expand All @@ -24,7 +24,7 @@ function GameForm() {
const delta =
isComplete &&
leaderboard.getGameDelta(
new Game("", new Date(), winnerTeam, loserTeam),
{ id: "", createdAt: Date.now(), winnerTeam, loserTeam },
leaderboard.getRankedPlayers()
);

Expand Down Expand Up @@ -78,9 +78,9 @@ function GameForm() {
{isAdding ? (
<>
<div className="flex justify-between px-4 items-center border-b border-slate-500">
<p className="text-lg font-bold">Winner</p>
<p className="text-xl font-bold">Winner</p>
{delta && <p className="text-lg">Δ {delta}</p>}
<p className="text-lg font-bold">Loser</p>
<p className="text-xl font-bold">Loser</p>
</div>
<div className="flex">
<div className="flex flex-col items-start flex-grow">
Expand Down
20 changes: 3 additions & 17 deletions domain/Game.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,12 @@
import { uniq } from "lodash";

import { PlayerId } from "./Player";

export type Team = [PlayerId, PlayerId];
export type GameId = string;
type Timestamp = number;

export class Game implements IGame {
constructor(
public readonly id: GameId,
public readonly createdAt: Date,
public readonly winnerTeam: Team,
public readonly loserTeam: Team
) {
if (uniq([...winnerTeam, ...loserTeam]).length !== 4) {
throw new Error("There must be four unique players.");
}
}
}

export interface IGame {
export interface Game {
id: GameId;
createdAt: Date;
createdAt: Timestamp;
winnerTeam: Team;
loserTeam: Team;
}
16 changes: 8 additions & 8 deletions domain/Leaderboard.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Game, IGame } from "./Game";
import { IPlayer, Player } from "./Player";
import { Game } from "./Game";
import { Player } from "./Player";

export interface RatedPlayer extends IPlayer {
export interface RatedPlayer extends Player {
rating: number;
}

export interface RatedGame extends IGame {
export interface RatedGame extends Game {
delta: number;
}

Expand All @@ -22,8 +22,8 @@ export class Leaderboard {
}));

this.games
.filter((game) => +game.createdAt < +date)
.sort((a, b) => +a.createdAt - +b.createdAt)
.filter((game) => game.createdAt < +date)
.sort((a, b) => a.createdAt - b.createdAt)
.forEach((game) => {
ratedPlayers = this.applyGame(game, ratedPlayers);
});
Expand All @@ -36,8 +36,8 @@ export class Leaderboard {
(player) => ({ ...player, rating: 1500 })
);

const { games, players } = this.games
.sort((a, b) => +a.createdAt - +b.createdAt)
const { games } = this.games
.sort((a, b) => a.createdAt - b.createdAt)
.reduce<{ games: RatedGame[]; players: RatedPlayer[] }>(
(curr, game) => {
const ratedPlayers = this.applyGame(game, curr.players);
Expand Down
11 changes: 1 addition & 10 deletions domain/Player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,7 @@ export type PlayerAnimal =
| "hedgehog"
| "kangaroo";

export class Player implements IPlayer {
constructor(
public readonly id: PlayerId,
public readonly name: string,
public readonly animal: PlayerAnimal,
public readonly isRetired: boolean
) {}
}

export interface IPlayer {
export interface Player {
id: PlayerId;
name: string;
animal: PlayerAnimal;
Expand Down
37 changes: 10 additions & 27 deletions pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import dynamic from "next/dynamic";
import Button from "../components/button";
import GameForm from "../components/game-form";
import GameList from "../components/game-list";
import { IGame } from "../domain/Game";
import { Game } from "../domain/Game";
import { Leaderboard } from "../domain/Leaderboard";
import { IPlayer, PlayerId } from "../domain/Player";
import { Player, PlayerId } from "../domain/Player";
import { UpstashGameRepository } from "../repository/UpstashGameRepository";
import { UpstashPlayerRepository } from "../repository/UpstashPlayerRepository";
import Card from "../components/card";
Expand All @@ -20,29 +20,17 @@ const PlayerList = dynamic(() => import("../components/player-list"), {
suspense: true,
});

const Home: NextPage<{ players: string; games: string }> = (props) => {
const [players, setPlayers] = useState<IPlayer[]>(JSON.parse(props.players));
const [games, setGames] = useState<IGame[]>(
JSON.parse(props.games).map((game: any) => ({
...game,
createdAt: new Date(game.createdAt),
}))
);
const Home: NextPage<{ players: Player[]; games: Game[] }> = (props) => {
const [players, setPlayers] = useState<Player[]>(props.players);
const [games, setGames] = useState<Game[]>(props.games);
const [tab, setTab] = useState<"games" | "players">("games");

function fetchPlayers() {
axios("/api/players").then(({ data }) => setPlayers(data));
}

function fetchGames() {
axios("/api/games").then(({ data }) =>
setGames(
data.map((game: IGame) => ({
...game,
createdAt: new Date(game.createdAt),
}))
)
);
axios("/api/games").then(({ data }) => setGames(data));
}

function getPlayer(id: PlayerId) {
Expand Down Expand Up @@ -120,10 +108,10 @@ const Home: NextPage<{ players: string; games: string }> = (props) => {
};

export const DataContext = createContext<{
players: IPlayer[];
players: Player[];
refreshPlayers: VoidFunction;
getPlayer: (id: PlayerId) => IPlayer;
games: IGame[];
getPlayer: (id: PlayerId) => Player;
games: Game[];
refreshGames: VoidFunction;
leaderboard: Leaderboard;
}>({
Expand All @@ -146,12 +134,7 @@ export async function getServerSideProps() {
playerRepository.listAll(),
]);

return {
props: {
games: JSON.stringify(games),
players: JSON.stringify(players),
},
};
return { props: { games, players } };
}

export default Home;
20 changes: 10 additions & 10 deletions repository/UpstashGameRepository.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import { Redis } from "@upstash/redis";
import { v4 as uuid } from "uuid";

import { Game, IGame, Team } from "../domain/Game";
import { Game, GameId, Team } from "../domain/Game";

const { set, del, mget, rpush, lrem, lrange } = Redis.fromEnv();

const GAME_LIST_KEY = "games";

export class UpstashGameRepository {
public async create(winnerTeam: Team, loserTeam: Team) {
const game = new Game(uuid(), new Date(), winnerTeam, loserTeam);
const game: Game = {
id: uuid(),
createdAt: Date.now(),
winnerTeam,
loserTeam,
};

await set(this.getGameKey(game.id), JSON.stringify(game));
await rpush(GAME_LIST_KEY, game.id);
}

public async delete(gameId: IGame["id"]) {
public async delete(gameId: GameId) {
await del(this.getGameKey(gameId));
await lrem(GAME_LIST_KEY, 0, gameId);
}
Expand All @@ -24,15 +29,10 @@ export class UpstashGameRepository {
const gameIds = await lrange(GAME_LIST_KEY, 0, -1);
const keys = gameIds.map(this.getGameKey);

const games = await mget(keys[0], ...keys.slice(1));

return games.map((data) => {
const { id, createdAt, winnerTeam, loserTeam } = data as IGame;
return new Game(id, new Date(createdAt), winnerTeam, loserTeam);
});
return await mget<Game[]>(keys[0], ...keys.slice(1));
}

private getGameKey(gameId: IGame["id"]) {
private getGameKey(gameId: GameId) {
return `GAME#${gameId}`;
}
}
22 changes: 11 additions & 11 deletions repository/UpstashPlayerRepository.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import { Redis } from "@upstash/redis";
import { v4 as uuid } from "uuid";

import { IPlayer, Player, PlayerAnimal } from "../domain/Player";
import { Player, PlayerAnimal, PlayerId } from "../domain/Player";

const { set, mget, del, rpush, lrem, lrange } = Redis.fromEnv();

const PLAYER_LIST_KEY = "players";

export class UpstashPlayerRepository {
public async create(name: string, animal: PlayerAnimal) {
const player = new Player(uuid(), name, animal, false);
const player: Player = {
id: uuid(),
name,
animal,
isRetired: false,
};

await set(this.getPlayerKey(player.id), JSON.stringify(player));
await rpush(PLAYER_LIST_KEY, player.id);
}

public async update(player: IPlayer) {
public async update(player: Player) {
await set(this.getPlayerKey(player.id), JSON.stringify(player));
}

public async delete(playerId: IPlayer["id"]) {
public async delete(playerId: PlayerId) {
await del(this.getPlayerKey(playerId));
await lrem(PLAYER_LIST_KEY, 0, playerId);
}
Expand All @@ -28,15 +33,10 @@ export class UpstashPlayerRepository {
const playerIds = await lrange(PLAYER_LIST_KEY, 0, -1);
const keys = playerIds.map(this.getPlayerKey);

const players = await mget(keys[0], ...keys.slice(1));

return players.map((data) => {
const { id, name, animal, isRetired } = data as IPlayer;
return new Player(id, name, animal, Boolean(isRetired));
});
return await mget<Player[]>(keys[0], ...keys.slice(1));
}

private getPlayerKey(playerId: IPlayer["id"]) {
private getPlayerKey(playerId: PlayerId) {
return `PLAYER#${playerId}`;
}
}

1 comment on commit 9d95310

@vercel
Copy link

@vercel vercel bot commented on 9d95310 Jun 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.