Skip to content

Commit

Permalink
feat(auth/v1.0): add admin side create user dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
IncognitoTGT committed Jul 23, 2024
1 parent a723a24 commit 7a8f730
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 81 deletions.
2 changes: 1 addition & 1 deletion src/app/(main)/admin/images/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default async function AdminPage() {
<Input id="img" placeholder="ghcr.io/spaceness/xxxx" name="dockerImage" required />
<Label htmlFor="icon">Icon</Label>
<Input id="icon" placeholder="Icon URL" name="icon" required />
<StyledSubmit>Submit</StyledSubmit>
<StyledSubmit>Save</StyledSubmit>
</form>
</DialogContent>
</Dialog>
Expand Down
52 changes: 51 additions & 1 deletion src/app/(main)/admin/users/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
import { StyledSubmit } from "@/components/submit-button";
import { Button } from "@/components/ui/button";
import { DataTable } from "@/components/ui/data-table";
import { db } from "@/lib/drizzle/db";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { db, user } from "@/lib/drizzle/db";
import { createId } from "@paralleldrive/cuid2";
import { hash } from "argon2";
import type { Metadata } from "next";
import { columns } from "./columns";
export const metadata: Metadata = {
Expand All @@ -17,6 +31,42 @@ export default async function AdminPage() {
<section className="-ml-8">
<DataTable data={data} columns={columns} />
</section>
<div className="flex justify-start items-center">
<Dialog>
<DialogTrigger asChild>
<Button className="ml-2">Add User</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Add User</DialogTitle>
<DialogDescription>The user will automatically be added after you click Save.</DialogDescription>
</DialogHeader>
<form
action={async (data) => {
"use server";
const userCheck = await db.query.user.findFirst({
where: (user, { eq }) => eq(user.email, data.get("email")?.toString() || ""),
});
if (userCheck) return;
await db.insert(user).values({
name: data.get("name")?.toString(),
email: data.get("email")?.toString() as string,
password: await hash(data.get("password")?.toString() as string),
id: createId(),
});
}}
className="flex flex-col gap-2 w-full"
>
<Label htmlFor="name">Name</Label>
<Input id="name" type="text" name="name" placeholder="Name" />
<Input id="email" type="email" name="email" placeholder="Email" required />
<Label htmlFor="password">Password</Label>
<Input minLength={8} id="password" type="password" name="password" placeholder="Password" required />
<StyledSubmit>Save</StyledSubmit>
</form>
</DialogContent>
</Dialog>
</div>
</div>
);
}
156 changes: 78 additions & 78 deletions src/app/auth/signup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,84 +14,84 @@ import { Info } from "lucide-react";
import { redirect, unstable_rethrow } from "next/navigation";

export default async function Page({
searchParams,
searchParams,
}: {
searchParams: { [key: string]: string | string[] | undefined };
searchParams: { [key: string]: string | string[] | undefined };
}) {
const session = await auth();
if (session) redirect("/");
const config = getConfig();
const { message, error } = searchParams;
if (!config.auth.credentials || !config.auth.credentials.signups)
redirect(`/auth/error?error=${encodeURIComponent("Signups are disabled for this instance.")}`);
return (
<CardContent className="m-1 w-full flex-col flex justify-center items-center">
<CardDescription>Create an account</CardDescription>
{message ? (
<Alert className="w-full my-4">
<Info className="h-4 w-4" />
<AlertTitle>{message}</AlertTitle>
</Alert>
) : null}
{error ? (
<Alert className="w-full my-4" variant="destructive">
<Info className="h-4 w-4" />
<AlertTitle>{error}</AlertTitle>
</Alert>
) : null}
<form
className="mx-auto mb-4 flex w-full flex-col items-start justify-center gap-2"
action={async (data) => {
"use server";
try {
if (!(await turnstileCheck(data))) {
redirect("/auth/signup?error=Failed%captcha");
}
const userCheck = await db.query.user.findFirst({
where: (user, { eq }) => eq(user.email, data.get("email")?.toString() || ""),
});
const users = await db.select().from(user)
if (userCheck) redirect("/auth/login?error=Email%20already%20in%20use");
await db.insert(user).values({
name: data.get("name")?.toString(),
email: data.get("email")?.toString() as string,
password: await hash(data.get("password")?.toString() as string),
id: createId(),
isAdmin: users.length === 0,
});
redirect("/auth/login?message=Account%20created%20successfully");
} catch (e) {
unstable_rethrow(e);
throw e;
}
}}
>
<Label htmlFor="name">Name</Label>
<Input id="name" type="text" name="name" placeholder="Name" autoComplete="name" className="w-full" />
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
name="email"
placeholder="Email"
autoComplete="email"
required
className="w-full"
/>
<Label htmlFor="password">Password</Label>
<Input
minLength={8}
id="password"
type="password"
name="password"
placeholder="Password"
autoComplete="new-password"
required
className="w-full"
/>
<Turnstile />
<StyledSubmit className="w-full">Sign up</StyledSubmit>
</form>
</CardContent>
);
const session = await auth();
if (session) redirect("/");
const config = getConfig();
const { message, error } = searchParams;
if (!config.auth.credentials || !config.auth.credentials.signups)
redirect(`/auth/error?error=${encodeURIComponent("Signups are disabled for this instance.")}`);
return (
<CardContent className="m-1 w-full flex-col flex justify-center items-center">
<CardDescription>Create an account</CardDescription>
{message ? (
<Alert className="w-full my-4">
<Info className="h-4 w-4" />
<AlertTitle>{message}</AlertTitle>
</Alert>
) : null}
{error ? (
<Alert className="w-full my-4" variant="destructive">
<Info className="h-4 w-4" />
<AlertTitle>{error}</AlertTitle>
</Alert>
) : null}
<form
className="mx-auto mb-4 flex w-full flex-col items-start justify-center gap-2"
action={async (data) => {
"use server";
try {
if (!(await turnstileCheck(data))) {
redirect("/auth/signup?error=Failed%captcha");
}
const userCheck = await db.query.user.findFirst({
where: (user, { eq }) => eq(user.email, data.get("email")?.toString() || ""),
});
const users = await db.select().from(user);
if (userCheck) redirect("/auth/login?error=Email%20already%20in%20use");
await db.insert(user).values({
name: data.get("name")?.toString(),
email: data.get("email")?.toString() as string,
password: await hash(data.get("password")?.toString() as string),
id: createId(),
isAdmin: users.length === 0,
});
redirect("/auth/login?message=Account%20created%20successfully");
} catch (e) {
unstable_rethrow(e);
throw e;
}
}}
>
<Label htmlFor="name">Name</Label>
<Input id="name" type="text" name="name" placeholder="Name" autoComplete="name" className="w-full" />
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
name="email"
placeholder="Email"
autoComplete="email"
required
className="w-full"
/>
<Label htmlFor="password">Password</Label>
<Input
minLength={8}
id="password"
type="password"
name="password"
placeholder="Password"
autoComplete="new-password"
required
className="w-full"
/>
<Turnstile />
<StyledSubmit className="w-full">Sign up</StyledSubmit>
</form>
</CardContent>
);
}
2 changes: 1 addition & 1 deletion src/components/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export default function Navigation({
url: "https://authjs.dev/",
},
];
const developers = ["incognitotgt", "1yusof", "genericness","uhidontkno"];
const developers = ["incognitotgt", "1yusof", "genericness", "uhidontkno"];
return (
<nav className="flex h-16 min-w-full items-center justify-between px-4">
<div className="flex items-center justify-start gap-2">
Expand Down

0 comments on commit 7a8f730

Please sign in to comment.