diff --git a/components/auth/components-auth-login-form.tsx b/components/auth/components-auth-login-form.tsx
index 0013f4e..4ba2449 100644
--- a/components/auth/components-auth-login-form.tsx
+++ b/components/auth/components-auth-login-form.tsx
@@ -2,67 +2,83 @@
import IconLockDots from '@/components/icon/icon-lock-dots';
import IconMail from '@/components/icon/icon-mail';
import { useRouter } from 'next/navigation';
-import { useState } from "react";
-import axios from "axios";
+import { useState } from 'react';
+import axios from 'axios';
import toast from 'react-hot-toast';
const ComponentsAuthLoginForm = () => {
- const [email, setEmail] = useState("")
- const [password, setPassword] = useState("")
- const [loading, setLoading] = useState(false)
- const router = useRouter()
+ const [email, setEmail] = useState('');
+ const [password, setPassword] = useState('');
+ const [loading, setLoading] = useState(false);
+ const router = useRouter();
- const submitForm = async (e: React.FormEvent) => {
- e.preventDefault()
-
- setLoading(true)
- try {
- const res = await axios.post(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/login`, {
- email,
- password,
- })
-
- localStorage.setItem("token", res.data.token)
-
- toast.success("Login successful!")
- router.push("/")
- } catch (err: any) {
- console.error("Login error:", err)
- toast.error(err.response?.data?.error || "Invalid credentials")
- } finally {
- setLoading(false)
- }
+ const submitForm = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setLoading(true);
+ try {
+ const res = await axios.post('/api/login', { email, password });
+ toast.success(res.data?.message || 'Login successful!');
+ router.push('/adminDashboard');
+ // token cookie is already set by the server:
+ } catch (err: any) {
+ console.error('Login error:', err);
+ const msg =
+ err?.response?.data?.message ||
+ err?.message ||
+ 'Invalid credentials';
+ toast.error(msg);
+ } finally {
+ setLoading(false);
}
+ };
- return (
-
- );
+ return (
+
+ );
};
export default ComponentsAuthLoginForm;
+
diff --git a/components/auth/components-auth-register-form.tsx b/components/auth/components-auth-register-form.tsx
index f5c2313..c48cfce 100644
--- a/components/auth/components-auth-register-form.tsx
+++ b/components/auth/components-auth-register-form.tsx
@@ -1,74 +1,131 @@
-'use client';
-import IconLockDots from '@/components/icon/icon-lock-dots';
-import IconMail from '@/components/icon/icon-mail';
-import IconUser from '@/components/icon/icon-user';
-import axios from 'axios';
-import { useRouter } from 'next/navigation';
-import { useState } from "react";
-import React from 'react';
-import toast from 'react-hot-toast';
+// components/auth/components-auth-register-form.tsx
+"use client";
-const ComponentsAuthRegisterForm = () => {
- const [email, setEmail] = useState("")
- const [password, setPassword] = useState("")
- const [loading, setLoading] = useState(false)
- const router = useRouter()
+import * as React from "react";
+import { useRouter } from "next/navigation";
- const submitForm = async(e: any) => {
- e.preventDefault()
-
- setLoading(true)
- try {
- const res = await axios.post(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/register`, {
- email,
- password,
- })
-
- localStorage.setItem("token", res.data.token)
-
- toast.success("Register successful!")
- router.push("/")
- } catch (err: any) {
- console.error("Register error:", err)
- toast.error(err.response?.data?.error || "Something went wrong")
- } finally {
- setLoading(false)
- }
- };
- return (
-
- );
+type Props = {
+ redirectTo?: string; // optional override
};
-export default ComponentsAuthRegisterForm;
+export default function ComponentsAuthRegisterForm({ redirectTo = "/dashboard" }: Props) {
+ const router = useRouter();
+ const [email, setEmail] = React.useState("");
+ const [password, setPassword] = React.useState("");
+ const [confirm, setConfirm] = React.useState("");
+ const [loading, setLoading] = React.useState(false);
+ const [error, setError] = React.useState(null);
+
+ async function onSubmit(e: React.FormEvent) {
+ e.preventDefault();
+ setError(null);
+
+ if (!email.trim() || !password) {
+ setError("Please fill in all fields.");
+ return;
+ }
+ if (password.length < 8) {
+ setError("Password must be at least 8 characters.");
+ return;
+ }
+ if (password !== confirm) {
+ setError("Passwords do not match.");
+ return;
+ }
+
+ try {
+ setLoading(true);
+ const res = await fetch("/api/register", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ email, password }),
+ });
+
+ const data = await res.json();
+
+ if (!res.ok) {
+ setError(data?.message || "Registration failed.");
+ return;
+ }
+
+ // Cookie is set by API; just route away
+ router.replace(redirectTo);
+ } catch (err) {
+ setError("Network error. Please try again.");
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ return (
+
+ );
+}
+
diff --git a/pages/api/login.ts b/pages/api/login.ts
index 2a5c6a6..8f3adff 100644
--- a/pages/api/login.ts
+++ b/pages/api/login.ts
@@ -1,15 +1,18 @@
-import { NextApiRequest, NextApiResponse } from "next";
+// pages/api/login.ts
+import type { NextApiRequest, NextApiResponse } from "next";
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
-const prisma = new PrismaClient()
+const prisma = new PrismaClient();
const SECRET_KEY = process.env.JWT_SECRET as string;
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" });
+ if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" });
- const { email, password } = req.body;
+ try {
+ const { email, password } = req.body as { email?: string; password?: string };
+ if (!email || !password) return res.status(400).json({ message: "Email and password are required" });
const user = await prisma.user.findUnique({ where: { email } });
if (!user) return res.status(401).json({ message: "Invalid credentials" });
@@ -17,8 +20,23 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(401).json({ message: "Invalid credentials" });
- const token = jwt.sign({ email: user.email }, SECRET_KEY, { expiresIn: "1d" });
+ const token = jwt.sign({ sub: user.id, email: user.email }, SECRET_KEY, { expiresIn: "1d" });
- res.setHeader("Set-Cookie", `token=${token}; HttpOnly; Path=/; Secure`);
- res.json({ token });
+ const isProd = process.env.NODE_ENV === "production";
+ const cookie = [
+ `token=${token}`,
+ "HttpOnly",
+ "Path=/",
+ "SameSite=Strict",
+ `Max-Age=${60 * 60 * 24}`, // 1 day
+ isProd ? "Secure" : "", // only secure in prod
+ ].filter(Boolean).join("; ");
+
+ res.setHeader("Set-Cookie", cookie);
+ return res.status(200).json({ message: "Login successful" });
+ } catch (e) {
+ console.error(e);
+ return res.status(500).json({ message: "Something went wrong" });
+ }
}
+
diff --git a/pages/api/register.ts b/pages/api/register.ts
index 3f66d80..0ab2b75 100644
--- a/pages/api/register.ts
+++ b/pages/api/register.ts
@@ -1,27 +1,42 @@
-import { NextApiRequest, NextApiResponse } from "next";
+// pages/api/register.ts
+import type { NextApiRequest, NextApiResponse } from "next";
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
-const prisma = new PrismaClient()
+const prisma = new PrismaClient();
const SECRET_KEY = process.env.JWT_SECRET as string;
-
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" });
+ if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" });
- const { email, password } = req.body;
+ try {
+ const { email, password } = req.body as { email?: string; password?: string };
+
+ if (!email || !password) return res.status(400).json({ message: "Email and password are required" });
const existingUser = await prisma.user.findUnique({ where: { email } });
if (existingUser) return res.status(400).json({ message: "User already exists" });
const hashedPassword = await bcrypt.hash(password, 10);
const user = await prisma.user.create({
- data: { email, password: hashedPassword },
+ data: { email, password: hashedPassword },
+ select: { id: true, email: true, createdAt: true }, // do NOT expose password
});
- const token = jwt.sign({ email: user.email }, SECRET_KEY, { expiresIn: "1d" });
+ const token = jwt.sign({ sub: user.id, email: user.email }, SECRET_KEY, { expiresIn: "1d" });
- res.setHeader("Set-Cookie", `token=${token}; HttpOnly; Path=/; Secure`);
- res.status(201).json({ message: "User registered", user, token });
+ // Set a secure, httpOnly cookie
+ const maxAge = 60 * 60 * 24; // 1 day
+ res.setHeader(
+ "Set-Cookie",
+ `token=${token}; HttpOnly; Path=/; Max-Age=${maxAge}; SameSite=Strict; Secure`
+ );
+
+ return res.status(201).json({ message: "User registered", user });
+ } catch (err) {
+ console.error(err);
+ return res.status(500).json({ message: "Something went wrong" });
+ }
}
+