Skip to content

Commit 5efc991

Browse files
committed
Updated package
1 parent 75fd825 commit 5efc991

24 files changed

+7380
-294
lines changed

app/layout.tsx

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import "@/styles/globals.css";
2+
import { Metadata } from "next";
3+
4+
export const metadata: Metadata = {
5+
title: "Nines Score",
6+
description: "Keep track of your nines score",
7+
viewport: "width=device-width, initial-scale=1, maximum-scale=1",
8+
icons: {
9+
apple: [{ url: "/apple-touch-icon.png", sizes: "180x180", type: "image/png" }],
10+
icon: [
11+
{ url: "/favicon-32x32.png", sizes: "32x32", type: "image/png" },
12+
{ url: "/favicon-16x16.png", sizes: "16x16", type: "image/png" },
13+
],
14+
other: [
15+
{ rel: "manifest", url: "/site.webmanifest" },
16+
{ rel: "mask-icon", url: "/safari-pinned-tab.svg", color: "#5bbad5" },
17+
],
18+
},
19+
themeColor: "#ffffff",
20+
other: {
21+
"msapplication-TileColor": "#da532c",
22+
},
23+
};
24+
25+
export default function RootLayout({ children }: { children: React.ReactNode }) {
26+
return (
27+
<html lang="en">
28+
<body>{children}</body>
29+
</html>
30+
);
31+
}

app/page.tsx

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"use client";
2+
3+
import { useState } from "react";
4+
import { GameScreen } from "@/components/GameScreen";
5+
import { ScoreView } from "@/components/ScoreView";
6+
import { StartScreen } from "@/components/StartScreen";
7+
import { getEmptyScores } from "@/funcs/global";
8+
import { Player } from "@/types/global";
9+
10+
export default function Home() {
11+
const [gameStarted, setGameStarted] = useState<boolean>(false);
12+
const [gameFinished, setGameFinished] = useState<boolean>(false);
13+
const [players, setPlayers] = useState<Player[]>([
14+
{ name: "", score: getEmptyScores(), jokers: getEmptyScores() },
15+
{ name: "", score: getEmptyScores(), jokers: getEmptyScores() },
16+
]);
17+
const [previousPlayers, setPreviousPlayers] = useState<Player[]>([]);
18+
const [previousRound, setPreviousRound] = useState<number>(0);
19+
return (
20+
<main className="flex flex-col justify-center min-h-screen gap-2 p-4 md:mx-auto md:max-w-md">
21+
{!gameFinished ? (
22+
<>
23+
{!gameStarted ? (
24+
<StartScreen
25+
players={players}
26+
previousPlayers={previousPlayers}
27+
previousRound={previousRound}
28+
setPlayers={setPlayers}
29+
setPreviousPlayers={setPreviousPlayers}
30+
setPreviousRound={setPreviousRound}
31+
setGameStarted={setGameStarted}
32+
/>
33+
) : (
34+
<GameScreen players={players} setPlayers={setPlayers} setGameFinished={setGameFinished} />
35+
)}
36+
</>
37+
) : (
38+
<ScoreView
39+
players={players}
40+
setPlayers={setPlayers}
41+
setGameStarted={setGameStarted}
42+
setGameFinished={setGameFinished}
43+
/>
44+
)}
45+
</main>
46+
);
47+
}

bun.lockb

-280 KB
Binary file not shown.

components/AddNewPlayerButton.tsx

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { getEmptyScores } from "@/funcs/global";
2+
import { Player } from "@/types/global";
3+
import { Dispatch, SetStateAction } from "react";
4+
5+
export const AddNewPlayerButton = ({
6+
players,
7+
setPlayers,
8+
}: {
9+
players: Player[];
10+
setPlayers: Dispatch<SetStateAction<Player[]>>;
11+
}) => {
12+
return (
13+
<button
14+
className="gap-2 btn btn-secondary"
15+
onClick={() => {
16+
if (players.length >= 6) {
17+
return;
18+
}
19+
setPlayers((prev) => {
20+
return [...prev, { name: "", score: getEmptyScores(), jokers: getEmptyScores() }];
21+
});
22+
}}
23+
>
24+
Add new Player
25+
</button>
26+
);
27+
};

components/ContinueGameButton.tsx

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Player } from "@/types/global";
2+
import { Dispatch, SetStateAction } from "react";
3+
4+
export const ContinueGameButton = ({
5+
previousPlayers,
6+
previousRound,
7+
setPlayers,
8+
setGameStarted,
9+
saveGameState,
10+
}: {
11+
previousPlayers: Player[];
12+
previousRound: number;
13+
setPlayers: Dispatch<SetStateAction<Player[]>>;
14+
setGameStarted: Dispatch<SetStateAction<boolean>>;
15+
saveGameState: (players: Player[], round: number) => void;
16+
}) => {
17+
if (previousPlayers.length === 0) {
18+
return null;
19+
}
20+
return (
21+
<div className="flex justify-center">
22+
<button
23+
className="btn btn-primary w-full"
24+
onClick={() => {
25+
saveGameState(previousPlayers, previousRound);
26+
setPlayers(previousPlayers);
27+
setGameStarted(true);
28+
}}
29+
>
30+
<span className="truncate">
31+
Continue Game ({previousPlayers.map((player) => player.name).join(", ")})
32+
</span>
33+
</button>
34+
</div>
35+
);
36+
};

components/GameScreen.tsx

+32-33
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
import { ChangeEvent, Dispatch, Fragment, SetStateAction, useEffect, useState } from "react";
2-
import { calculateTotalScore, finishedGame, getAllRounds, loadGameState, saveGameState } from "../funcs/global";
3-
import { Player } from "../types/global";
4-
import { themeChange } from "theme-change";
5-
import { Simulate } from "react-dom/test-utils";
6-
import load = Simulate.load;
1+
import { Dispatch, Fragment, SetStateAction, useEffect, useState } from "react";
2+
import { calculateTotalScore, finishedGame, getAllRounds, loadGameState, saveGameState } from "@/funcs/global";
3+
import { Player } from "@/types/global";
74

8-
interface GameScreenProps {
5+
export const GameScreen = ({
6+
players,
7+
setPlayers,
8+
setGameFinished,
9+
}: {
910
players: Player[];
1011
setPlayers: Dispatch<SetStateAction<Player[]>>;
1112
setGameFinished: Dispatch<SetStateAction<boolean>>;
12-
}
13-
14-
export const GameScreen = ({ players, setPlayers, setGameFinished }: GameScreenProps) => {
13+
}) => {
1514
const rounds = getAllRounds();
16-
const [currentRound, setCurrentRound] = useState<number>(0);
15+
const [currentRound, setCurrentRound] = useState(0);
1716

1817
useEffect(() => {
1918
const gameState = loadGameState();
@@ -23,25 +22,8 @@ export const GameScreen = ({ players, setPlayers, setGameFinished }: GameScreenP
2322
}
2423
}, []);
2524

26-
function updateScore(event: ChangeEvent<HTMLInputElement>, index: number) {
27-
const newPlayers = [...players];
28-
newPlayers[index].score[rounds[currentRound]] = parseFloat(event.target.value) || 0;
29-
setPlayers(newPlayers);
30-
saveGameState(newPlayers, currentRound);
31-
}
32-
33-
function updateJokers(amountOfJokers: number, index: number) {
34-
const newPlayers = [...players];
35-
newPlayers[index].jokers[rounds[currentRound]] = amountOfJokers;
36-
setPlayers(newPlayers);
37-
saveGameState(newPlayers, currentRound);
38-
}
39-
40-
function endGame() {
41-
setGameFinished(true);
42-
finishedGame();
43-
}
4425
const amountOfJokers = [0, 1, 2, 3, 4, 5, 6, 7];
26+
4527
return (
4628
<>
4729
<p className="text-5xl">
@@ -64,15 +46,25 @@ export const GameScreen = ({ players, setPlayers, setGameFinished }: GameScreenP
6446
className="w-3/4 input input-bordered"
6547
placeholder="0"
6648
value={player.score[rounds[currentRound]]}
67-
onChange={(e) => updateScore(e, index)}
49+
onChange={(e) => {
50+
const newPlayers = [...players];
51+
newPlayers[index].score[rounds[currentRound]] = parseFloat(e.target.value) || 0;
52+
setPlayers(newPlayers);
53+
saveGameState(newPlayers, currentRound);
54+
}}
6855
/>
6956
</div>
7057
<span>Amount of Jokers: (optional)</span>
7158
<div className="w-full flex gap-2">
7259
{amountOfJokers.map((joker) => (
7360
<span
7461
key={joker}
75-
onClick={() => updateJokers(joker, index)}
62+
onClick={() => {
63+
const newPlayers = [...players];
64+
newPlayers[index].jokers[rounds[currentRound]] = joker;
65+
setPlayers(newPlayers);
66+
saveGameState(newPlayers, currentRound);
67+
}}
7668
className={`flex cursor-pointer items-center justify-center grow rounded-lg p-2 border border-gray-400 ${
7769
player.jokers[rounds[currentRound]] === joker && "bg-primary text-white"
7870
}`}
@@ -83,7 +75,7 @@ export const GameScreen = ({ players, setPlayers, setGameFinished }: GameScreenP
8375
</div>
8476
<hr></hr>
8577
</Fragment>
86-
))}{" "}
78+
))}
8779
<div className="flex justify-between">
8880
<button
8981
className="gap-2 btn btn-primary"
@@ -93,7 +85,14 @@ export const GameScreen = ({ players, setPlayers, setGameFinished }: GameScreenP
9385
</button>
9486
<button
9587
className="gap-2 btn btn-primary"
96-
onClick={() => (currentRound + 1 < rounds.length ? setCurrentRound(currentRound + 1) : endGame())}
88+
onClick={() => {
89+
if (currentRound + 1 < rounds.length) {
90+
setCurrentRound(currentRound + 1);
91+
} else {
92+
setGameFinished(true);
93+
finishedGame();
94+
}
95+
}}
9796
>
9897
Next Round
9998
</button>

components/PlayAgainButton.tsx

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Dispatch, SetStateAction } from "react";
2+
import { Player } from "@/types/global";
3+
import { getEmptyScores } from "@/funcs/global";
4+
5+
export const PlayAgainButton = ({
6+
setPlayers,
7+
setGameFinished,
8+
setGameStarted,
9+
}: {
10+
setPlayers: Dispatch<SetStateAction<Player[]>>;
11+
setGameFinished: Dispatch<SetStateAction<boolean>>;
12+
setGameStarted: Dispatch<SetStateAction<boolean>>;
13+
}) => {
14+
return (
15+
<button
16+
className="self-start gap-2 btn btn-secondary"
17+
onClick={() => {
18+
setPlayers((currentPlayers) => {
19+
const players = [...currentPlayers];
20+
return players.map((player) => {
21+
return {
22+
...player,
23+
score: getEmptyScores(),
24+
};
25+
});
26+
});
27+
setGameFinished(false);
28+
setGameStarted(false);
29+
}}
30+
>
31+
Play Again
32+
</button>
33+
);
34+
};

components/PlayersInput.tsx

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Player } from "@/types/global";
2+
import { Dispatch, SetStateAction } from "react";
3+
4+
export const PlayersInput = ({
5+
players,
6+
setPlayers,
7+
}: {
8+
players: Player[];
9+
setPlayers: Dispatch<SetStateAction<Player[]>>;
10+
}) => {
11+
return players.map((player, index) => (
12+
<input
13+
key={index}
14+
type="text"
15+
placeholder={`Player ${index + 1}`}
16+
className="w-full input input-bordered"
17+
value={player.name}
18+
onChange={(e) => {
19+
setPlayers((currentPlayers) => {
20+
const newPlayers = [...currentPlayers];
21+
newPlayers[index].name = e.target.value;
22+
return newPlayers;
23+
});
24+
}}
25+
/>
26+
));
27+
};

components/ScoreGraph.tsx

+11-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { Player } from "../types/global";
2-
31
import {
42
Chart as ChartJS,
53
CategoryScale,
@@ -10,14 +8,15 @@ import {
108
Tooltip,
119
Legend,
1210
} from "chart.js";
11+
1312
import { Line } from "react-chartjs-2";
14-
import { getAllRounds, getColors } from "../funcs/global";
13+
14+
import { getAllRounds, getColors } from "@/funcs/global";
15+
import { Player } from "@/types/global";
16+
1517
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend);
16-
interface ScoreGraphProps {
17-
players: Player[];
18-
}
1918

20-
function getCumulativeArray(arr: number[]): number[] {
19+
function getCumulativeArray({ arr }: { arr: number[] }): number[] {
2120
const cumulativeArr = [arr[0]];
2221

2322
for (let i = 1; i < arr.length; i++) {
@@ -27,21 +26,21 @@ function getCumulativeArray(arr: number[]): number[] {
2726
return cumulativeArr;
2827
}
2928

30-
export const ScoreGraph = ({ players }: ScoreGraphProps) => {
29+
export const ScoreGraph = ({ players }: { players: Player[] }) => {
3130
const labels = getAllRounds();
3231
const colors = getColors();
3332
const datasets = players.map((player, index) => {
3433
return {
3534
label: player.name,
36-
data: getCumulativeArray(
37-
labels.map((label, index) => {
35+
data: getCumulativeArray({
36+
arr: labels.map((label) => {
3837
const roundScore = player.score[label];
3938
if (typeof roundScore === "number") {
4039
return roundScore;
4140
}
4241
return 0;
43-
})
44-
),
42+
}),
43+
}),
4544
fill: false,
4645
borderColor: colors[index % colors.length],
4746
tension: 0.1,
@@ -63,7 +62,6 @@ export const ScoreGraph = ({ players }: ScoreGraphProps) => {
6362
},
6463
},
6564
};
66-
console.log({ data, options });
6765

6866
return (
6967
<div>

0 commit comments

Comments
 (0)