Skip to content

Commit bb8a340

Browse files
authored
Merge pull request #54 from scape76/add-user-results-to-db
Keep track of user's records (challenge results) in database
2 parents 78253c3 + c1bc7db commit bb8a340

File tree

10 files changed

+106
-8
lines changed

10 files changed

+106
-8
lines changed

.env.example

+3
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,8 @@ DATABASE_URL="postgresql://postgres:example@localhost:5432/postgres"
88
GITHUB_CLIENT_ID="63b03dd1a029181eede8"
99
GITHUB_CLIENT_SECRET="fe61fec0056b571d01d0a1e25945904237d164e8"
1010

11+
# to generate, run
12+
# openssl rand -base64 172 | tr -d '\n'
13+
# in your terminal
1114
NEXTAUTH_SECRET="my_ultra_secure_nextauth_secret"
1215
NEXTAUTH_URL="http://localhost:3000"

next.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ const nextConfig = {
33
images: {
44
domains: ["avatars.githubusercontent.com"],
55
},
6+
experimental: {
7+
serverActions: true,
8+
},
69
};
710

811
module.exports = nextConfig;

prisma/schema.prisma

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ model User {
1616
image String?
1717
accounts Account[]
1818
sessions Session[]
19+
results Result[]
1920
}
2021

2122
// Necessary for Next auth
@@ -52,3 +53,10 @@ model VerificationToken {
5253
5354
@@unique([identifier, token])
5455
}
56+
57+
model Result {
58+
id String @id @default(cuid())
59+
takenTime String
60+
userId String
61+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
62+
}

src/app/_actions/result.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"use server";
2+
3+
import { User } from "@prisma/client";
4+
import { prisma } from "@/lib/prisma";
5+
6+
export async function saveUserResult(input: {
7+
userId: User["id"];
8+
timeTaken: string | number;
9+
}) {
10+
if (typeof input.timeTaken !== "string" && typeof input.timeTaken !== "number") {
11+
throw new Error("Invalid input.");
12+
}
13+
14+
await prisma.result.create({
15+
data: {
16+
userId: input.userId,
17+
takenTime: input.timeTaken.toString(),
18+
},
19+
});
20+
}

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

+33-5
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,49 @@ declare module "next-auth" {
1313

1414
export const nextAuthOptions = {
1515
adapter: PrismaAdapter(prisma),
16+
session: {
17+
strategy: 'jwt',
18+
},
19+
secret: process.env.NEXTAUTH_SECRET!,
1620
providers: [
1721
GithubProvider({
1822
clientId: process.env.GITHUB_CLIENT_ID!,
1923
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
2024
}),
2125
],
2226
callbacks: {
23-
session({ session, user }) {
24-
if (session.user) {
25-
session.user.id = user.id;
27+
async jwt({ token, user }) {
28+
const dbUser = await prisma.user.findFirst({
29+
where: {
30+
email: token.email,
31+
},
32+
});
33+
34+
if (!dbUser) {
35+
if (user) {
36+
token.id = user.id;
37+
}
38+
return token;
39+
}
40+
41+
return {
42+
id: dbUser.id,
43+
name: dbUser.name,
44+
email: dbUser.email,
45+
picture: dbUser.image,
46+
};
47+
},
48+
async session({ token, session }) {
49+
if (token) {
50+
session.user.id = token.id;
51+
session.user.name = token.name;
52+
session.user.email = token.email;
53+
session.user.image = token.picture;
2654
}
2755

2856
return session;
29-
}
30-
}
57+
},
58+
},
3159
} satisfies AuthOptions;
3260

3361
const handler = NextAuth(nextAuthOptions);

src/app/page.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Header from "@/components/header";
22
import { Button } from "@/components/ui/button";
33
import { LoginButton, LogoutButton } from "@/components/ui/buttons";
4-
import { getSession } from "@/lib/getSession";
4+
import { getSession } from "@/lib/session";
55
import { prisma } from "@/lib/prisma";
66
import Image from "next/image";
77

src/app/race/page.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import TypingCode from "@/components/typing/typingCode";
2+
import { getCurrentUser } from "@/lib/session";
23

34
export default async function Race() {
5+
const user = await getCurrentUser();
6+
7+
console.log(user);
8+
49
return (
510
<>
611
<main className="flex min-h-screen flex-col items-center justify-between p-24">
7-
<TypingCode />
12+
<TypingCode user={user}/>
813
</main>
914
</>
1015
);

src/components/typing/typingCode.tsx

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@
33
import { useState, useEffect } from "react";
44

55
import DisplayedCode from "./displayedCode";
6+
import type { User } from "next-auth";
7+
import { saveUserResult } from "@/app/_actions/result";
68
import { Input } from "@/components/ui/input";
79
import { Button } from "@/components/ui/button";
810

911
const code = `printf("hello world")`;
1012

11-
export default function TypingCode() {
13+
interface TypingCodeProps {
14+
user?: User;
15+
}
16+
17+
export default function TypingCode({ user }: TypingCodeProps) {
1218
const [input, setInput] = useState("");
1319
const [startTime, setStartTime] = useState<Date | null>(null);
1420
const [endTime, setEndTime] = useState<Date | null>(null);
@@ -20,6 +26,8 @@ export default function TypingCode() {
2026
const timeTaken: number =
2127
(endTime.getTime() - startTime.getTime()) / 1000;
2228

29+
if (user) saveUserResult({ userId: user.id, timeTaken });
30+
2331
console.log("Time taken:", timeTaken);
2432
}
2533
}, [endTime, startTime]);

src/lib/getSession.ts renamed to src/lib/session.ts

+6
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,9 @@ import { getServerSession } from "next-auth";
44
export function getSession() {
55
return getServerSession(nextAuthOptions);
66
}
7+
8+
export async function getCurrentUser() {
9+
const session = await getSession();
10+
11+
return session?.user;
12+
}

src/types/next-auth.d.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { User } from "next-auth";
2+
3+
type UserId = string;
4+
5+
declare module "next-auth/jwt" {
6+
interface JWT {
7+
id: UserId;
8+
}
9+
}
10+
11+
declare module "next-auth" {
12+
interface Session {
13+
user: User & {
14+
id: UserId;
15+
};
16+
}
17+
}

0 commit comments

Comments
 (0)