diff --git a/bun.lockb b/bun.lockb index 47b9e14..5043618 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 5655ad7..1b22df7 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "@trpc/react-query": "^11.0.0-rc.446", "@trpc/server": "^11.0.0-rc.446", "@types/bcrypt": "^5.0.2", + "@types/lodash": "^4.17.7", "@types/loglevel": "^1.6.3", "@types/react-copy-to-clipboard": "^5.0.7", "bcrypt": "^5.1.1", diff --git a/src/app/(site)/(auth)/register/page.tsx b/src/app/(site)/(auth)/register/page.tsx index e497c07..7824faf 100644 --- a/src/app/(site)/(auth)/register/page.tsx +++ b/src/app/(site)/(auth)/register/page.tsx @@ -49,113 +49,3 @@ const RegisterPage: React.FC = () => { }; export default RegisterPage; - -// const SignUpPage = () => { -// const router = useRouter(); -// -// const signup = api.auth.create.useMutation({ -// onSuccess: () => router.push("/auth/signin"), -// onError: (error) => { -// logger.error("signup", "error", error); -// }, -// }); -// const [userInfo, setUserInfo] = React.useState({ -// email: "fergal.moran+opengifame@gmail.com", -// password: "secret", -// repeatPassword: "secret", -// }); -// -// return ( -//
-//
-//

-// Create new account -//

-//
-// -//
-//
-//
{ -// e.preventDefault(); -// signup.mutate(userInfo); -// }} -// method="post" -// > -//
-// -//
-// -// setUserInfo({ ...userInfo, email: target.value }) -// } -// className="input input-bordered w-full" -// /> -//
-//
-// -//
-// -//
-// -// setUserInfo({ ...userInfo, password: target.value }) -// } -// className="input input-bordered w-full" -// /> -//
-//
-//
-// -//
-// -// setUserInfo({ ...userInfo, repeatPassword: target.value }) -// } -// className="input input-bordered w-full" -// /> -//
-//
-// -//
-// -//
-//
-// -//
-// -//
-//
-//
-//
-// ); -// }; -// -// export default SignUpPage; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index d920f48..57b2271 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,27 +1,30 @@ import { Inter as FontSans } from "next/font/google"; import "@/styles/globals.css"; -import { type Metadata } from "next"; +import { type Metadata, Viewport } from "next"; import { TRPCReactProvider } from "@/trpc/react"; import { cn } from "@/lib/utils"; import { ThemeProvider } from "next-themes"; import { TailwindIndicator } from "@/components/tailwind-indicator"; import { Toaster } from "@/components/ui/toaster"; +import React from "react"; const fontSans = FontSans({ subsets: ["latin"], variable: "--font-sans", }); +export const viewport: Viewport = { + themeColor: [ + { media: "(prefers-color-scheme: light)", color: "white" }, + { media: "(prefers-color-scheme: dark)", color: "black" }, + ], +}; export const metadata: Metadata = { title: "Open Gifame", description: "Contains traces of gifs", icons: [{ rel: "icon", url: "/favicon.ico" }], - themeColor: [ - { media: "(prefers-color-scheme: light)", color: "white" }, - { media: "(prefers-color-scheme: dark)", color: "black" }, - ], }; export default function RootLayout({ diff --git a/src/components/forms/auth/RegistrationForm.tsx b/src/components/forms/auth/RegistrationForm.tsx index 98b22d5..9cb37ba 100644 --- a/src/components/forms/auth/RegistrationForm.tsx +++ b/src/components/forms/auth/RegistrationForm.tsx @@ -19,6 +19,8 @@ import { logger } from "@/lib/logger"; import { Icons } from "@/components/icons"; import { cn } from "@/lib/utils"; import { toast } from "sonner"; +import { useRouter } from "next/navigation"; + const registrationSchema = z .object({ email: z.string().email({ message: "Invalid email address" }), @@ -41,6 +43,7 @@ type RegistrationFormValues = z.infer; const RegistrationForm: React.FC = () => { const [isLoading, setIsLoading] = React.useState(false); + const router = useRouter(); const form = useForm({ resolver: zodResolver(registrationSchema), }); @@ -52,6 +55,7 @@ const RegistrationForm: React.FC = () => { try { await createUser.mutateAsync(data); toast("User registered successfully"); + router.push("/signin"); } catch (error) { logger.error("RegistrationForm", "error", error); toast("Failed to register user"); @@ -68,6 +72,7 @@ const RegistrationForm: React.FC = () => { ( Email @@ -85,6 +90,7 @@ const RegistrationForm: React.FC = () => { ( Password @@ -102,6 +108,7 @@ const RegistrationForm: React.FC = () => { ( Confirm password diff --git a/src/server/api/routers/auth.ts b/src/server/api/routers/auth.ts index e6259f0..6802220 100644 --- a/src/server/api/routers/auth.ts +++ b/src/server/api/routers/auth.ts @@ -2,6 +2,7 @@ import { createTRPCRouter, publicProcedure } from "../trpc"; import { z } from "zod"; import { users } from "@/server/db/schema"; import bcrypt from "bcrypt"; +import { and, eq } from "drizzle-orm"; export const authRouter = createTRPCRouter({ create: publicProcedure @@ -14,4 +15,19 @@ export const authRouter = createTRPCRouter({ }); return user; }), + + login: publicProcedure + .input(z.object({ email: z.string().email(), password: z.string().min(5) })) + .query(async ({ ctx, input }) => { + const hashedPassword = await bcrypt.hash(input.password, 10); + const user = await ctx.db + .select() + .from(users) + .where( + and(eq(users.email, input.email), eq(users.password, hashedPassword)), + ) + .limit(1); + + return user[0]; + }), }); diff --git a/src/server/auth.ts b/src/server/auth.ts index 41fd773..cdd6ba5 100644 --- a/src/server/auth.ts +++ b/src/server/auth.ts @@ -4,9 +4,9 @@ import { getServerSession, type DefaultSession, type NextAuthOptions, + RequestInternal, } from "next-auth"; import { type Adapter } from "next-auth/adapters"; -import { db } from "@/server/db"; import { accounts, sessions, @@ -15,33 +15,18 @@ import { } from "@/server/db/schema"; import { api } from "@/trpc/server"; import { env } from "@/env"; +import { db } from "@/server/db"; + +import Credentials from "next-auth/providers/credentials"; -/** - * Module augmentation for `next-auth` types. Allows us to add custom properties to the `session` - * object and keep type safety. - * - * @see https://next-auth.js.org/getting-started/typescript#module-augmentation - */ declare module "next-auth" { interface Session extends DefaultSession { user: { id: string; - // ...other properties - // role: UserRole; } & DefaultSession["user"]; } - - // interface User { - // // ...other properties - // // role: UserRole; - // } } -/** - * Options for NextAuth.js used to configure adapters, providers, callbacks, etc. - * - * @see https://next-auth.js.org/configuration/options - */ export const authOptions: NextAuthOptions = { callbacks: { session: ({ session, user }) => ({ @@ -59,13 +44,13 @@ export const authOptions: NextAuthOptions = { verificationTokensTable: verificationTokens, }) as Adapter, providers: [ - CredentialsProvider({ - type: "credentials", + Credentials({ + name: "credentials", credentials: { email: { label: "Email", type: "email" }, password: { label: "Password", type: "password" }, }, - authorize: async (credentials, request) => { + authorize: async (credentials, _request) => { if (!credentials) { return null; } @@ -73,30 +58,14 @@ export const authOptions: NextAuthOptions = { email: credentials.email, password: credentials.password, }); - // const user = await prisma.users.findUnique({ - // where: { email: credentials.email }, - // select: { - // id: true, - // email: true, - // password: true, - // }, - // }); - // if (user && user.password) { - // const hashed = await confirmPassword( - // credentials.password, - // user.password, - // ); - // if (hashed) { - // return omit(user, "password"); - // } - // } - return null; + if (!result) { + return null; + } + return { id: result.id, email: result.email }; }, }), ], - session: { - strategy: "jwt", - }, + secret: env.NEXTAUTH_SECRET, debug: env.NODE_ENV === "development", pages: {