Skip to content

Commit

Permalink
add name form
Browse files Browse the repository at this point in the history
  • Loading branch information
minhd-vu committed Feb 27, 2024
1 parent 60597a1 commit e920e1c
Show file tree
Hide file tree
Showing 15 changed files with 173 additions and 73 deletions.
3 changes: 1 addition & 2 deletions app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const options: NextAuthOptions = {
],
callbacks: {
async signIn({ user }: { user: User | AdapterUser }) {
if (!user.email || !user.name) {
if (!user.email) {
return false;
}

Expand All @@ -33,7 +33,6 @@ const options: NextAuthOptions = {
await prisma.user.create({
data: {
email: user.email,
name: user.name,
},
});
}
Expand Down
5 changes: 1 addition & 4 deletions app/api/party/join/route.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { PartyJoinBody } from "@/lib/party";
import prisma from "@/lib/prisma";
import { getServerSession } from "next-auth";

type PartyJoinBody = {
code?: string;
};

export async function POST(req: Request) {
const session = await getServerSession();
if (!session?.user?.email) {
Expand Down
24 changes: 0 additions & 24 deletions app/api/user/[id]/route.ts

This file was deleted.

35 changes: 35 additions & 0 deletions app/api/user/[name]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import prisma from "@/lib/prisma";

export async function GET(
_: Request,
{ params }: { params: { name: string } },
) {
const users = await prisma.user.findMany({
where: {
name: {
equals: params.name,
mode: "insensitive",
},
},
select: {
name: true,
kills: true,
deaths: true,
wins: true,
},
});

if (users.length > 1) {
return Response.json(`More than one user with name ${params.name} found`, {
status: 500,
});
}

if (users.length === 0) {
return Response.json(`Could not find user with name ${params.name}`, {
status: 400,
});
}

return Response.json(users[0]);
}
47 changes: 46 additions & 1 deletion app/api/user/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getUser } from "@/lib/user";
import { UserBody, getUser } from "@/lib/user";
import { getServerSession } from "next-auth";
import prisma from "@/lib/prisma";

export async function GET() {
const session = await getServerSession();
Expand All @@ -10,3 +11,47 @@ export async function GET() {
const user = await getUser(session.user.email);
return Response.json(user);
}

export async function POST(req: Request) {
const session = await getServerSession();
if (!session?.user?.email) {
return Response.json(null, { status: 401 });
}

const body: UserBody = await req.json();
const name = body.name?.trim();

if (!name) {
return Response.json("Name cannot be empty", { status: 400 });
}

if (!name.match(/^[0-9a-zA-Z]+$/)) {
return Response.json("Name must be alphanumeric", { status: 400 });
}

if (name.length > 16) {
return Response.json("Name must be <= 16 characters", { status: 400 });
}

let user = await prisma.user.findFirst({
where: {
name: {
equals: name,
mode: "insensitive",
},
},
});

if (user) {
return Response.json("Name is already taken", { status: 400 });
}

user = await prisma.user.update({
where: { email: session.user.email },
data: {
name,
},
});

return Response.json(user);
}
25 changes: 1 addition & 24 deletions app/leaderboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,5 @@
import LeaderboardRow from "@/components/LeaderboardRow";
import prisma from "@/lib/prisma";

async function getLeaderboardUsers() {
return await prisma.user.findMany({
select: {
id: true,
name: true,
kills: true,
deaths: true,
wins: true,
},
orderBy: [
{
wins: "desc",
},
{
kills: "desc",
},
{
deaths: "asc",
},
],
});
}
import { getLeaderboardUsers } from "@/lib/user";

export default async function Leaderboard() {
const users = await getLeaderboardUsers();
Expand Down
12 changes: 8 additions & 4 deletions app/user/[id]/page.tsx → app/user/[name]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import prisma from "@/lib/prisma";

export default async function UserById({ params }: { params: { id: string } }) {
const id = params.id;
const user = await prisma.user.findUnique({ where: { id } });
export default async function UserById({
params,
}: {
params: { name: string };
}) {
const name = params.name;
const user = await prisma.user.findUnique({ where: { name } });

if (!user) {
return <p>No user found with id {id}</p>;
return <p>No user found with name {name}</p>;
}

return (
Expand Down
11 changes: 4 additions & 7 deletions components/JoinParty.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,20 @@ import { useContext } from "react";
import { Controller, SubmitHandler, useForm } from "react-hook-form";
import { useSWRConfig } from "swr";
import { ErrorContext } from "./App";

type Inputs = {
code: string;
};
import { PartyJoinBody } from "@/lib/party";

export default function JoinParty() {
const { mutate } = useSWRConfig();
const { handleSubmit, control } = useForm<Inputs>();
const { handleSubmit, control } = useForm<PartyJoinBody>();
const { setError } = useContext(ErrorContext);

const onSubmit: SubmitHandler<Inputs> = async ({ code }) => {
const onSubmit: SubmitHandler<PartyJoinBody> = async ({ code }) => {
const res = await fetch("/api/party/join", {
method: "POST",
headers: {
"Content-type": "application/json",
},
body: JSON.stringify({ code: code.toLowerCase() }),
body: JSON.stringify({ code: code?.toLowerCase() }),
});

if (!res.ok) {
Expand Down
2 changes: 1 addition & 1 deletion components/LeaderboardRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default function LeaderboardRow({
const router = useRouter();

async function onClick() {
router.push(`/user/${user.id}`);
router.push(`/user/${user.name}`);
}

return (
Expand Down
53 changes: 53 additions & 0 deletions components/NameForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"use client";

import { useContext } from "react";
import { Controller, SubmitHandler, useForm } from "react-hook-form";
import { useSWRConfig } from "swr";
import { ErrorContext } from "./App";
import { UserBody } from "@/lib/user";

export default function NameForm() {
const { mutate } = useSWRConfig();
const { handleSubmit, control } = useForm<UserBody>();
const { setError } = useContext(ErrorContext);

const onSubmit: SubmitHandler<UserBody> = async ({ name }) => {
const res = await fetch("/api/user", {
method: "POST",
headers: {
"Content-type": "application/json",
},
body: JSON.stringify({ name }),
});

if (!res.ok) {
setError(await res.json());
return;
}

mutate("/api/user");
};

return (
<form onSubmit={handleSubmit(onSubmit)}>
<h1 className="text-3xl">Set Username</h1>
<p className="text-center">
Please choose a username. You won't be able to change this in the
future.
</p>
<Controller
name="name"
control={control}
render={({ field }) => (
<input
{...field}
className="input input-bordered"
placeholder="Username"
required
/>
)}
/>
<button className="btn btn-primary">Save</button>
</form>
);
}
2 changes: 1 addition & 1 deletion components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default async function Navbar() {
<ul className="menu menu-horizontal px-2">
{user && (
<li>
<a href={`/user/${user.id}`}>Profile</a>
<a href={`/user/${user.name}`}>Profile</a>
</li>
)}
<li>
Expand Down
5 changes: 5 additions & 0 deletions components/Party.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { User } from "@/lib/user";
import ConfirmKill from "./ConfirmKill";
import DenyKill from "./DenyKill";
import Player from "./Player";
import NameForm from "./NameForm";

export default function Party() {
const fetcher: Fetcher<User, string> = (url) =>
Expand All @@ -38,6 +39,10 @@ export default function Party() {
return <Alert>User not found. Try logging in.</Alert>;
}

if (!user.name) {
return <NameForm />;
}

const party = user.party;
if (!party) {
return (
Expand Down
4 changes: 4 additions & 0 deletions lib/party.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import _ from "lodash";
import prisma from "./prisma";

export type PartyJoinBody = {
code?: string;
};

export async function removePlayer(email: string) {
const user = await prisma.user.findUniqueOrThrow({
where: {
Expand Down
12 changes: 10 additions & 2 deletions lib/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import prisma from "./prisma";
export type User = Awaited<ReturnType<typeof getUser>>;
export type Party = NonNullable<User["party"]>;

export type UserBody = {
name?: string;
};

export async function getUser(email: string) {
return await prisma.user.findUniqueOrThrow({
where: {
Expand All @@ -23,10 +27,14 @@ export async function getUser(email: string) {
export type LeaderboardUsers = Awaited<ReturnType<typeof getLeaderboardUsers>>;
export type LeaderboardUser = LeaderboardUsers[0];

async function getLeaderboardUsers() {
export async function getLeaderboardUsers() {
return await prisma.user.findMany({
where: {
name: {
not: null,
},
},
select: {
id: true,
name: true,
kills: true,
deaths: true,
Expand Down
6 changes: 3 additions & 3 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ generator client {
}

model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String? @unique
alive Boolean @default(false)
pending Boolean @default(false)
Expand Down

0 comments on commit e920e1c

Please sign in to comment.