Skip to content

Commit

Permalink
feat: credential auth
Browse files Browse the repository at this point in the history
  • Loading branch information
Security2431 committed Dec 10, 2023
1 parent e39355b commit 6adabab
Show file tree
Hide file tree
Showing 11 changed files with 403 additions and 29 deletions.
1 change: 1 addition & 0 deletions apps/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@trpc/next": "^10.40.0",
"@trpc/react-query": "^10.40.0",
"@trpc/server": "^10.40.0",
"argon2": "^0.31.2",
"classnames": "^2.3.2",
"date-fns": "^2.30.0",
"emoji-picker-react": "^4.5.7",
Expand Down
9 changes: 2 additions & 7 deletions apps/nextjs/src/app/_components/auth-showcase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ export async function AuthShowcase({ provider }: Props) {

if (!session) {
return (
<SignIn
provider={provider}
className="rounded-full bg-white/10 px-10 py-3 font-semibold no-underline transition hover:bg-white/20"
>
<SignIn provider={provider}>
Sign in with {provider.charAt(0).toUpperCase() + provider.slice(1)}
</SignIn>
);
Expand All @@ -27,9 +24,7 @@ export async function AuthShowcase({ provider }: Props) {
{session && <span>Logged in as {session.user.name}</span>}
</p>

<SignOut className="rounded-full bg-white/10 px-10 py-3 font-semibold no-underline transition hover:bg-white/20">
Sign out
</SignOut>
<SignOut>Sign out</SignOut>
</div>
);
}
2 changes: 2 additions & 0 deletions apps/nextjs/src/app/_components/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const Button = forwardRef<Ref, Props>(
{
"border border-white bg-transparent px-4 py-2 text-white no-underline hover:border-transparent hover:bg-white hover:text-purple-500":
variant === "primary",
"rounded-full bg-white/10 px-10 py-3 font-semibold no-underline transition hover:bg-white/20":
variant === "secondary",
"p-0 text-white hover:underline": variant === "link",
},
className,
Expand Down
69 changes: 69 additions & 0 deletions apps/nextjs/src/app/_components/credential-auth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"use client";

import { useRouter } from "next/navigation";
import { zodResolver } from "@hookform/resolvers/zod";
import { signIn } from "next-auth/react";
import type { SubmitHandler } from "react-hook-form";
import { FormProvider, useForm } from "react-hook-form";
import { toast } from "react-toastify";
import * as z from "zod";

import Button from "./button";
import Field from "./form/Field";

/* Local constants & types
============================================================================= */
export type FormData = z.infer<typeof schemaValidation>;

const schemaValidation = z.object({
email: z.string(),
password: z.string(),
});

const CredentialAuth = () => {
const router = useRouter();
const methods = useForm<FormData>({
resolver: zodResolver(schemaValidation),
defaultValues: {
email: "",
password: "",
},
});

const onSubmit: SubmitHandler<FormData> = async (data: FormData) => {
try {
const response = await signIn("credentials", {
...data,
redirect: false,
});

console.log({ response });
if (!response?.error) {
router.push("/workspaces");
router.refresh();
}
} catch (error) {
console.error(error);
toast.error("Invalid email or password");
}
};

return (
<form
method="post"
className="flex w-full flex-col gap-4"
onSubmit={methods.handleSubmit(onSubmit)}
>
<FormProvider {...methods}>
<Field label="Email:" name="email" type="email" />
<Field label="Password:" name="password" type="password" />

<Button type="submit" variant="secondary">
Sign In
</Button>
</FormProvider>
</form>
);
};

export default CredentialAuth;
2 changes: 1 addition & 1 deletion apps/nextjs/src/app/_components/form/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type Props = InputHTMLAttributes<HTMLInputElement>;
/* <Input />
============================================================================= */
const Input = forwardRef<Ref, Props>(
({ onClick, className, type, ...props }, ref) => (
({ onClick, className, type = "text", ...props }, ref) => (
<input
className={classNames(
"mb-0 block w-full appearance-none rounded border border-white bg-transparent bg-clip-padding px-3 py-2 text-sm text-white backdrop-blur transition placeholder:text-gray-400 disabled:cursor-not-allowed disabled:text-white disabled:opacity-50",
Expand Down
5 changes: 4 additions & 1 deletion apps/nextjs/src/app/_components/form/Label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ const Label = forwardRef<Ref, Props>(
<label
ref={ref}
htmlFor={htmlFor}
className={classNames("mb-1 text-sm font-semibold uppercase", className)}
className={classNames(
"mb-1 text-left text-sm font-semibold uppercase",
className,
)}
{...props}
/>
),
Expand Down
17 changes: 16 additions & 1 deletion apps/nextjs/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { redirect } from "next/navigation";
import { auth } from "@acme/auth";

import { AuthShowcase } from "./_components/auth-showcase";
import CredentialAuth from "./_components/credential-auth";
import Heading from "./_components/heading";
import { Meteors } from "./_components/meteors";
import routes from "./_lib/routes";
Expand All @@ -27,7 +28,21 @@ export default async function HomePage() {
with 2day.report!
</p>

<AuthShowcase provider="github" />
<CredentialAuth />

<p
className="my-6 flex items-center overflow-hidden text-center text-xs uppercase before:relative
before:right-2 before:inline-block before:h-[1px] before:w-1/2
before:bg-white before:align-middle after:relative after:left-2
after:inline-block after:h-[1px] after:w-1/2 after:bg-white after:align-middle"
>
or
</p>

<div className="flex flex-col gap-4">
<AuthShowcase provider="google" />
<AuthShowcase provider="github" />
</div>

<Meteors number={10} />
</div>
Expand Down
21 changes: 14 additions & 7 deletions apps/nextjs/src/components/auth.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
import type { ComponentProps } from "react";

import type { OAuthProviders } from "@acme/auth";
import { CSRF_experimental } from "@acme/auth";

import Button from "~/app/_components/button";

export function SignIn({
provider,
...props
}: { provider: OAuthProviders } & ComponentProps<"button">) {
}: {
provider: OAuthProviders;
children: React.ReactNode;
}) {
return (
<form action={`/api/auth/signin/${provider}`} method="post">
<button {...props} />
<Button variant="secondary" type="submit" className="w-full">
{props.children}
</Button>
<CSRF_experimental />
</form>
);
}

export function SignOut(props: ComponentProps<"button">) {
export function SignOut(props: { children: React.ReactNode }) {
return (
<form action="/api/auth/signout" method="post">
<button {...props} />
<form action="/api/auth/signout" method="post" className="w-full">
<Button variant="secondary" type="submit">
{props.children}
</Button>
<CSRF_experimental />
</form>
);
Expand Down
5 changes: 5 additions & 0 deletions packages/api/src/router/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ export const userRouter = createTRPCRouter({
.query(({ ctx, input }) => {
return ctx.prisma.user.findFirst({ where: { id: input.id } });
}),
byEmail: protectedProcedure
.input(z.object({ email: z.string().min(1) }))
.query(({ ctx, input }) => {
return ctx.prisma.user.findFirst({ where: { email: input.email } });
}),
create: publicProcedure
.input(
z.object({
Expand Down
Loading

0 comments on commit 6adabab

Please sign in to comment.