Skip to content

Commit c1bc7db

Browse files
authored
Merge branch 'main' into add-user-results-to-db
2 parents a41ee93 + 78253c3 commit c1bc7db

36 files changed

+2345
-44
lines changed

package-lock.json

+1,010-15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+8-5
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,33 @@
1313
"@auth/prisma-adapter": "^1.0.0",
1414
"@next-auth/prisma-adapter": "^1.0.7",
1515
"@prisma/client": "^4.16.2",
16+
"@radix-ui/react-dropdown-menu": "^2.0.5",
1617
"@radix-ui/react-slot": "^1.0.2",
1718
"class-variance-authority": "^0.6.1",
1819
"clsx": "^1.2.1",
1920
"lucide-react": "^0.259.0",
2021
"next": "13.4.9",
2122
"next-auth": "^4.22.1",
23+
"next-themes": "^0.2.1",
2224
"postcss": "8.4.25",
2325
"react": "18.2.0",
2426
"react-dom": "18.2.0",
27+
"recharts": "^2.7.2",
2528
"tailwind-merge": "^1.13.2",
2629
"tailwindcss": "3.3.2",
2730
"tailwindcss-animate": "^1.0.6",
2831
"typescript": "5.1.6"
2932
},
3033
"devDependencies": {
31-
"@typescript-eslint/eslint-plugin": "^5.61.0",
32-
"@typescript-eslint/parser": "^5.61.0",
33-
"eslint-plugin-jsx-a11y": "^6.7.1",
34-
"prisma": "^4.16.2",
3534
"@types/node": "20.4.1",
3635
"@types/react": "18.2.14",
3736
"@types/react-dom": "18.2.6",
37+
"@typescript-eslint/eslint-plugin": "^5.61.0",
38+
"@typescript-eslint/parser": "^5.61.0",
39+
"autoprefixer": "10.4.14",
3840
"eslint": "8.44.0",
3941
"eslint-config-next": "13.4.9",
40-
"autoprefixer": "10.4.14"
42+
"eslint-plugin-jsx-a11y": "^6.7.1",
43+
"prisma": "^4.16.2"
4144
}
4245
}

public/placeholder-image.jpg

744 KB
Loading

src/app/api/auth/[...nextauth]/route.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
import { prisma } from "@/lib/prisma";
22
import { PrismaAdapter } from "@next-auth/prisma-adapter";
3-
import NextAuth, { AuthOptions } from "next-auth";
3+
import NextAuth, { AuthOptions, DefaultSession } from "next-auth";
44
import GithubProvider from "next-auth/providers/github";
55

6+
declare module "next-auth" {
7+
interface Session extends DefaultSession {
8+
user: {
9+
id: string;
10+
} & DefaultSession["user"];
11+
}
12+
}
13+
614
export const nextAuthOptions = {
715
adapter: PrismaAdapter(prisma),
816
session: {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { prisma } from "@/lib/prisma";
2+
3+
const handler = async (request: Request) => {
4+
const object = await request.json();
5+
const uid = request.headers.get("Authorization")?.split("userId ")[1];
6+
const newName = object.newName;
7+
console.log(newName)
8+
if (!newName) {
9+
return new Response(
10+
"name-is-empty",
11+
{ status: 400 }
12+
);
13+
};
14+
15+
prisma.$connect;
16+
17+
await prisma.$executeRaw`UPDATE "User" SET name = ${newName} WHERE id = ${uid}`;
18+
19+
prisma.$disconnect;
20+
21+
return new Response("success!", { status: 200 });
22+
};
23+
24+
export {
25+
handler as POST
26+
};

src/app/dashboard/page.tsx

+204-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,210 @@
1+
"use client";
2+
3+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
4+
import {
5+
Table,
6+
TableBody,
7+
TableCell,
8+
TableHead,
9+
TableHeader,
10+
TableRow,
11+
} from "@/components/ui/table";
112
import React from "react";
13+
import {
14+
LineChart,
15+
ComposedChart,
16+
Line,
17+
XAxis,
18+
YAxis,
19+
CartesianGrid,
20+
Tooltip,
21+
Legend,
22+
ResponsiveContainer,
23+
} from "recharts";
224

325
export default function DashboardPage() {
26+
// List of recent games.
27+
const recentGames = [
28+
{
29+
gameId: "cljvlqkcz000008l424hi4l4c",
30+
date: "03/02/2023",
31+
accuracy: 92,
32+
errors: 2,
33+
wpm: 42,
34+
},
35+
{
36+
gameId: "cljvlqpag000208l47as7d9h4",
37+
date: "06/02/2023",
38+
accuracy: 89,
39+
errors: 2,
40+
wpm: 65,
41+
},
42+
{
43+
gameId: "cljvlqsj8000408l4ahr36soj",
44+
date: "08/02/2023",
45+
accuracy: 78,
46+
errors: 2,
47+
wpm: 80,
48+
},
49+
{
50+
gameId: "cljvlqsj8000448ewhr36soj",
51+
date: "08/02/2023",
52+
accuracy: 78,
53+
errors: 2,
54+
wpm: 80,
55+
},
56+
];
57+
// Accuracy data of the player in the matches
58+
const accuracyData = [
59+
{ gameNumber: 1, score: 95.1 },
60+
{ gameNumber: 2, score: 89.1 },
61+
{ gameNumber: 3, score: 95.1 },
62+
{ gameNumber: 4, score: 91.1 },
63+
{ gameNumber: 5, score: 99.1 },
64+
{ gameNumber: 6, score: 95.1 },
65+
{ gameNumber: 7, score: 93.1 },
66+
{ gameNumber: 8, score: 95.1 },
67+
{ gameNumber: 9, score: 95.1 },
68+
{ gameNumber: 10, score: 95.1 },
69+
];
70+
// Words per minute data.
71+
const wpmData = [
72+
{ gameNumber: 1, wpm: 20 },
73+
{ gameNumber: 2, wpm: 50 },
74+
{ gameNumber: 3, wpm: 30 },
75+
{ gameNumber: 4, wpm: 50 },
76+
];
77+
// All achievements and the progress of finishing it. NOTE: This should be sorted on progress.
78+
const achievements = [
79+
{
80+
id: "cljvlqsj8000408l4ahr36soj",
81+
title: "First race",
82+
description: "Started a race",
83+
progress: 100,
84+
},
85+
{
86+
id: "cljvlqsj8000408l4ahr36sok",
87+
title: "Play 10 races",
88+
description: "Play a total of 10 races online",
89+
progress: 33,
90+
},
91+
];
92+
493
return (
5-
<div>
6-
<div>Coming soon...</div>
7-
</div>
94+
<>
95+
<h1 className="text-4xl m-6 font-bold text-center max-[600px]:mb-10">
96+
Dashboard
97+
</h1>
98+
<div className="flex max-[600px]:flex-col justify-center items-center w-screen h-[50vh] gap-6 m-2">
99+
<Card className="w-[47.5%] max-[600px]:w-[100%] max-[600px]:mr-4 h-full max-[600px]:h-[50%]">
100+
<CardHeader>
101+
<CardTitle className="text-center m-2">Accuracy</CardTitle>
102+
</CardHeader>
103+
<ResponsiveContainer height="100%">
104+
<LineChart
105+
data={accuracyData}
106+
margin={{ right: 25, left: 25, bottom: 100 }}
107+
>
108+
<CartesianGrid strokeDasharray="3 3" />
109+
<XAxis dataKey="gameNumber" />
110+
<YAxis dataKey="score" />
111+
<Tooltip />
112+
<Legend />
113+
<Line
114+
type="monotone"
115+
dataKey="score"
116+
stroke="#82ca9d"
117+
activeDot={{ r: 6 }}
118+
/>
119+
</LineChart>
120+
</ResponsiveContainer>
121+
</Card>
122+
<Card className="w-[47.5%] max-[600px]:w-[100%] h-full max-[600px]:h-[50%] max-[600px]:mr-4 max-[600px]:ml-4 max-[600px]:mb-6">
123+
<CardHeader>
124+
<CardTitle className="text-center m-2">Words per minute</CardTitle>
125+
</CardHeader>
126+
<ResponsiveContainer height="100%">
127+
<ComposedChart
128+
data={wpmData}
129+
margin={{ right: 25, left: 25, bottom: 100 }}
130+
>
131+
<CartesianGrid strokeDasharray="3 3" />
132+
<XAxis dataKey="gameNumber" />
133+
<YAxis dataKey="wpm" />
134+
<Tooltip />
135+
<Legend />
136+
<Line
137+
type="monotone"
138+
dataKey="wpm"
139+
stroke="#0da2ff"
140+
activeDot={{ r: 6 }}
141+
/>
142+
</ComposedChart>
143+
</ResponsiveContainer>
144+
</Card>
145+
</div>
146+
<div className="flex max-[850px]:flex-col justify-center items-center w-screen min-[850px]:h-[50vh] gap-4 m-4">
147+
<Card className="w-[55vw] max-[850px]:w-[100vw] min-[850px]:h-[50vh] mr-4 p-4">
148+
<CardHeader>
149+
<CardTitle className="text-center m-2">Recent Races</CardTitle>
150+
</CardHeader>
151+
<Table className="w-full max-[600px]:text-sm">
152+
<TableHeader>
153+
<TableRow>
154+
<TableHead className="max-[900px]:hidden">Game ID</TableHead>
155+
<TableHead>Errors</TableHead>
156+
<TableHead>Accuracy</TableHead>
157+
<TableHead>Wpm</TableHead>
158+
<TableHead>Date</TableHead>
159+
</TableRow>
160+
</TableHeader>
161+
<TableBody>
162+
{recentGames.map((game) => {
163+
return (
164+
<TableRow key={game.gameId}>
165+
<TableCell className="max-[900px]:hidden">
166+
{game.gameId}
167+
</TableCell>
168+
<TableCell className="text-red-600 hover:text-red-500">
169+
{game.wpm} Errors
170+
</TableCell>
171+
<TableCell>{game.accuracy}%</TableCell>
172+
<TableCell>{game.wpm} Wpm</TableCell>
173+
<TableCell>{game.date}</TableCell>
174+
</TableRow>
175+
);
176+
})}
177+
</TableBody>
178+
</Table>
179+
</Card>
180+
<Card className="w-[40vw] max-[850px]:w-screen min-[850px]:h-[50vh] mr-4">
181+
<CardHeader>
182+
<CardTitle className="text-center m-2">Achievements</CardTitle>
183+
</CardHeader>
184+
{achievements.map((achievement) => {
185+
return (
186+
<Card
187+
className="m-4 p-2 flex justify-between"
188+
key={achievement.id}
189+
>
190+
<CardHeader>
191+
<CardTitle>{achievement.title}</CardTitle>
192+
<CardDescription>{achievement.description}</CardDescription>
193+
</CardHeader>
194+
{achievement.progress > 50 ? (
195+
<p className="font-normal text-green-500 mt-auto mb-auto mr-2">
196+
{achievement.progress}%
197+
</p>
198+
) : (
199+
<p className="font-normal text-yellow-400 mt-auto mb-auto mr-2">
200+
{achievement.progress}%
201+
</p>
202+
)}
203+
</Card>
204+
);
205+
})}
206+
</Card>
207+
</div>
208+
</>
8209
);
9210
}

src/app/globals.css

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
--ring: 215 20.2% 65.1%;
3535

3636
--radius: 0.5rem;
37+
38+
--monochrome-color: 0 0% 0%;
3739
}
3840

3941
.dark {
@@ -65,6 +67,8 @@
6567
--destructive-foreground: 0 85.7% 97.3%;
6668

6769
--ring: 217.2 32.6% 17.5%;
70+
71+
--monochrome-color: 0 0% 100%;
6872
}
6973
}
7074

src/app/layout.tsx

+9-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import "./globals.css";
33
import type { Metadata } from "next";
44
import { Inter } from "next/font/google";
55

6+
import { Footer } from "@/components/footer";
7+
import { ThemeProvider } from "@/components/theme-provider"
8+
69
const inter = Inter({ subsets: ["latin"] });
710

811
export const metadata: Metadata = {
@@ -11,15 +14,18 @@ export const metadata: Metadata = {
1114
};
1215

1316
export default function RootLayout({
14-
children,
17+
children
1518
}: {
1619
children: React.ReactNode;
1720
}) {
1821
return (
1922
<html lang="en">
2023
<body className={inter.className}>
21-
<Header />
22-
{children}
24+
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
25+
<Header />
26+
{children}
27+
<Footer />
28+
</ThemeProvider>
2329
</body>
2430
</html>
2531
);

0 commit comments

Comments
 (0)