diff --git a/.vscode/settings.json b/.vscode/settings.json
index d94e71c..cae72af 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,3 @@
{
- "workbench.colorTheme": "City Lights"
+ "workbench.colorTheme": "Tinacious Design (High Contrast)"
}
\ No newline at end of file
diff --git a/bun.lockb b/bun.lockb
index 5043618..fb08ec3 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/package.json b/package.json
index 1b22df7..867e8c4 100644
--- a/package.json
+++ b/package.json
@@ -14,8 +14,8 @@
"start": "next start"
},
"dependencies": {
- "@auth/drizzle-adapter": "^1.1.0",
- "@headlessui/react": "^2.1.4",
+ "@auth/drizzle-adapter": "^1.4.2",
+ "@headlessui/react": "^2.1.5",
"@hookform/resolvers": "^3.9.0",
"@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-alert-dialog": "^1.1.1",
@@ -45,8 +45,8 @@
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
- "@t3-oss/env-nextjs": "^0.10.1",
- "@tanstack/react-query": "^5.50.0",
+ "@t3-oss/env-nextjs": "^0.11.1",
+ "@tanstack/react-query": "^5.54.1",
"@trpc/client": "^11.0.0-rc.446",
"@trpc/react-query": "^11.0.0-rc.446",
"@trpc/server": "^11.0.0-rc.446",
@@ -62,19 +62,19 @@
"date-fns": "^3.6.0",
"drizzle-orm": "^0.33.0",
"embla-carousel-react": "^8.2.1",
- "geist": "^1.3.0",
+ "geist": "^1.3.1",
"input-otp": "^1.2.4",
"lodash": "^4.17.21",
"loglevel": "^1.9.1",
"loglevel-plugin-prefix": "^0.8.4",
"lucide-react": "^0.438.0",
- "next": "^14.2.4",
+ "next": "^14.2.8",
"next-auth": "^4.24.7",
"next-themes": "^0.3.0",
"postgres": "^3.4.4",
"react": "^18.3.1",
"react-copy-to-clipboard": "^5.1.0",
- "react-day-picker": "8.10.1",
+ "react-day-picker": "9.0.8",
"react-dom": "^18.3.1",
"react-hook-form": "^7.53.0",
"react-icons": "^5.3.0",
@@ -85,25 +85,25 @@
"superjson": "^2.2.1",
"tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7",
- "vaul": "^0.9.1",
+ "vaul": "^0.9.2",
"zod": "^3.23.8"
},
"devDependencies": {
- "@types/eslint": "^8.56.10",
- "@types/node": "^20.14.10",
- "@types/react": "^18.3.3",
+ "@types/eslint": "^9.6.1",
+ "@types/node": "^22.5.4",
+ "@types/react": "^18.3.5",
"@types/react-dom": "^18.3.0",
- "@typescript-eslint/eslint-plugin": "^8.1.0",
- "@typescript-eslint/parser": "^8.1.0",
- "drizzle-kit": "^0.24.0",
- "eslint": "^8.57.0",
- "eslint-config-next": "^14.2.4",
+ "@typescript-eslint/eslint-plugin": "^8.4.0",
+ "@typescript-eslint/parser": "^8.4.0",
+ "drizzle-kit": "^0.24.2",
+ "eslint": "^9.9.1",
+ "eslint-config-next": "^14.2.8",
"eslint-plugin-drizzle": "^0.2.3",
- "postcss": "^8.4.39",
- "prettier": "^3.3.2",
- "prettier-plugin-tailwindcss": "^0.6.5",
- "tailwindcss": "^3.4.3",
- "typescript": "^5.5.3"
+ "postcss": "^8.4.45",
+ "prettier": "^3.3.3",
+ "prettier-plugin-tailwindcss": "^0.6.6",
+ "tailwindcss": "^3.4.10",
+ "typescript": "^5.5.4"
},
"ct3aMetadata": {
"initVersion": "7.37.0"
diff --git a/src/app/(site)/(auth)/layout.tsx b/src/app/(site)/(auth)/layout.tsx
index a8e6032..67c2cef 100644
--- a/src/app/(site)/(auth)/layout.tsx
+++ b/src/app/(site)/(auth)/layout.tsx
@@ -1,7 +1,30 @@
+import Link from "next/link";
+import { Icons } from "@/components/icons";
+import { cn } from "@/lib/utils";
+import { buttonVariants } from "@/components/ui/button";
interface AuthLayoutProps {
children: React.ReactNode;
}
export default function AuthLayout({ children }: AuthLayoutProps) {
- return
{children}
;
+ return (
+
+
+
+ <>
+
+ Back
+ >
+
+
+ {children}
+
+
+ );
}
diff --git a/src/app/(site)/(auth)/register/page.tsx b/src/app/(site)/(auth)/register/page.tsx
index 7824faf..39066b8 100644
--- a/src/app/(site)/(auth)/register/page.tsx
+++ b/src/app/(site)/(auth)/register/page.tsx
@@ -10,40 +10,22 @@ import { buttonVariants } from "@/components/ui/button";
const RegisterPage: React.FC = () => {
return (
-
-
- <>
-
- Back
- >
-
-
-
-
-
- Welcome back
-
-
- Enter your email to sign in to your account
-
-
-
-
-
-
- Don't have an account? Sign Up
-
-
+
+
+
+
Welcome
+
Register for an account
+
+
+
+
+ Already have an account? Login?
+
+
);
};
diff --git a/src/app/(site)/(auth)/signin/page.tsx b/src/app/(site)/(auth)/signin/page.tsx
index 9bb8e58..f2e7d82 100644
--- a/src/app/(site)/(auth)/signin/page.tsx
+++ b/src/app/(site)/(auth)/signin/page.tsx
@@ -2,121 +2,31 @@
import SocialLogin from "@/components/widgets/login/SocialLogin";
import Link from "next/link";
import React from "react";
-import { logger } from "@/lib/logger";
-import { signIn } from "next-auth/react";
+import { Icons } from "@/components/icons";
+import { cn } from "@/lib/utils";
+import { buttonVariants } from "@/components/ui/button";
+import SignInForm from "@/components/forms/auth/SignInForm";
const SignInPage = () => {
- const [userInfo, setUserInfo] = React.useState({
- email: "fergal.moran+opengifame@gmail.com",
- password: "secret",
- });
-
return (
-
-
-
- Sign in to your account
-
-
- Or
-
- create a new account
-
+
+
+
+
Welcome back
+
+ Enter your email to sign in to your account
-
-
+
+
+
+
+ Don't have an account? Sign Up
+
+
);
};
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 71d36ad..6366cd0 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -18,6 +18,8 @@ export default async function Home() {
+
+
{JSON.stringify(session, null, 2)}
{session?.user &&
}
diff --git a/src/components/forms/auth/SignInForm.tsx b/src/components/forms/auth/SignInForm.tsx
new file mode 100644
index 0000000..777d341
--- /dev/null
+++ b/src/components/forms/auth/SignInForm.tsx
@@ -0,0 +1,128 @@
+// src/components/RegistrationForm.tsx
+import React from "react";
+import { useForm } from "react-hook-form";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { z } from "zod";
+import { Button, buttonVariants } from "@/components/ui/button";
+import {
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from "@/components/ui/form";
+import { Input } from "@/components/ui/input";
+import { api } from "@/trpc/react";
+import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
+import { logger } from "@/lib/logger";
+import { Icons } from "@/components/icons";
+import { cn } from "@/lib/utils";
+import { toast } from "sonner";
+import { useRouter } from "next/navigation";
+import { signIn } from "next-auth/react";
+
+const signInSchema = z.object({
+ email: z.string().email({ message: "Invalid email address" }),
+ password: z
+ .string()
+ .min(5, { message: "Password must be at least 5 characters long" }),
+});
+
+type SignInFormValues = z.infer
;
+
+const SignInForm: React.FC = () => {
+ const [isLoading, setIsLoading] = React.useState(false);
+ const router = useRouter();
+ const form = useForm({
+ resolver: zodResolver(signInSchema),
+ });
+
+ const onSubmit = async (data: SignInFormValues) => {
+ setIsLoading(true);
+ try {
+ const result = await signIn("credentials", {
+ redirect: false,
+ email: data.email,
+ password: data.password,
+ });
+ logger.debug("signin", "result", result);
+ if (result?.status === 200) {
+ router.push("/");
+ }
+ } catch (error) {
+ logger.error("SignInForm", "error", error);
+ toast("Failed to signin user");
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return (
+
+
+ );
+};
+
+export default SignInForm;
diff --git a/src/server/api/routers/auth.ts b/src/server/api/routers/auth.ts
index 6802220..0bf0d4e 100644
--- a/src/server/api/routers/auth.ts
+++ b/src/server/api/routers/auth.ts
@@ -16,18 +16,4 @@ 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 cdd6ba5..4c4414d 100644
--- a/src/server/auth.ts
+++ b/src/server/auth.ts
@@ -1,10 +1,8 @@
import { DrizzleAdapter } from "@auth/drizzle-adapter";
-import CredentialsProvider from "next-auth/providers/credentials";
import {
getServerSession,
type DefaultSession,
type NextAuthOptions,
- RequestInternal,
} from "next-auth";
import { type Adapter } from "next-auth/adapters";
import {
@@ -13,11 +11,12 @@ import {
users,
verificationTokens,
} 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";
+import bcrypt from "bcrypt";
+import { and, eq } from "drizzle-orm";
declare module "next-auth" {
interface Session extends DefaultSession {
@@ -29,13 +28,18 @@ declare module "next-auth" {
export const authOptions: NextAuthOptions = {
callbacks: {
- session: ({ session, user }) => ({
- ...session,
- user: {
- ...session.user,
- id: user.id,
- },
- }),
+ session: ({ session, user }) => {
+ const s = {
+ ...session,
+ user: {
+ ...session.user
+ },
+ };
+ return s;
+ },
+ },
+ session: {
+ strategy: "jwt",
},
adapter: DrizzleAdapter(db, {
usersTable: users,
@@ -54,14 +58,24 @@ export const authOptions: NextAuthOptions = {
if (!credentials) {
return null;
}
- const result = await api.auth.login({
- email: credentials.email,
- password: credentials.password,
- });
- if (!result) {
+ const user = await db
+ .select()
+ .from(users)
+ .where(and(eq(users.email, credentials.email)))
+ .limit(1);
+
+ if (!user || user.length < 1) {
return null;
}
- return { id: result.id, email: result.email };
+ if (
+ !(await bcrypt.compare(
+ credentials.password,
+ user[0]!.password as string,
+ ))
+ ) {
+ return null;
+ }
+ return { id: user[0]!.id, email: user[0]!.email };
},
}),
],