feat: Enhance login error reporting with backend pre-validation and update signup to require email verification instead of auto-login.

This commit is contained in:
pradeepkumar
2025-12-22 13:02:17 +05:30
parent 060643fed8
commit 6c6129e8d1
3 changed files with 96 additions and 62 deletions

View File

@@ -18,19 +18,41 @@ export default function LoginPage() {
setLoading(true); setLoading(true);
setError(''); setError('');
const result = await signIn('credentials', { try {
email, // First, validate credentials with backend to get proper error messages
password, const validateRes = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/auth/login`, {
redirect: false, method: 'POST',
}); headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
setLoading(false); const validateData = await validateRes.json();
if (result?.error) { if (!validateRes.ok) {
setError('Invalid email or password'); // Show the actual error message from backend
} else { setError(validateData.message || 'Invalid email or password');
router.push('/'); setLoading(false);
router.refresh(); return;
}
// If validation passed, use NextAuth to create session
const result = await signIn('credentials', {
email,
password,
redirect: false,
});
setLoading(false);
if (result?.error) {
setError('Login failed. Please try again.');
} else {
router.push('/');
router.refresh();
}
} catch (err) {
setLoading(false);
setError('An error occurred. Please try again.');
} }
}; };

View File

@@ -1,7 +1,6 @@
'use client'; 'use client';
import { useState } from 'react'; import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { signIn } from 'next-auth/react'; import { signIn } from 'next-auth/react';
import Link from 'next/link'; import Link from 'next/link';
import { authService, AuthService, RegisterRequest } from '@/services'; import { authService, AuthService, RegisterRequest } from '@/services';
@@ -14,7 +13,6 @@ interface ValidationError {
} }
export default function SignUpPage() { export default function SignUpPage() {
const router = useRouter();
const [userType, setUserType] = useState<UserType>('USER'); const [userType, setUserType] = useState<UserType>('USER');
const [firstName, setFirstName] = useState(''); const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState(''); const [lastName, setLastName] = useState('');
@@ -24,6 +22,7 @@ export default function SignUpPage() {
const [error, setError] = useState(''); const [error, setError] = useState('');
const [fieldErrors, setFieldErrors] = useState<ValidationError[]>([]); const [fieldErrors, setFieldErrors] = useState<ValidationError[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [registrationSuccess, setRegistrationSuccess] = useState(false);
const getFieldError = (fieldName: string): string | null => { const getFieldError = (fieldName: string): string | null => {
const fieldError = fieldErrors.find((e) => e.field === fieldName); const fieldError = fieldErrors.find((e) => e.field === fieldName);
@@ -47,19 +46,8 @@ export default function SignUpPage() {
await authService.register(registerData); await authService.register(registerData);
// Auto login after successful registration // Show success message - user must verify email before logging in
const result = await signIn('credentials', { setRegistrationSuccess(true);
email,
password,
redirect: false,
});
if (result?.error) {
router.push('/login');
} else {
router.push('/');
router.refresh();
}
} catch (err) { } catch (err) {
// Get field errors // Get field errors
const errors = AuthService.getFieldErrors(err); const errors = AuthService.getFieldErrors(err);
@@ -90,15 +78,41 @@ export default function SignUpPage() {
/> />
</div> </div>
{/* Sign Up Heading */} {/* Registration Success Message */}
<div className="text-center mb-6"> {registrationSuccess ? (
<h2 className="text-[30px] font-normal text-[#00293d] mb-3">Sign Up</h2> <div className="bg-white rounded-[20px] p-8 shadow-sm">
<p className="text-sm text-[#00293d] px-4 leading-relaxed"> <div className="text-center">
Sign in or create an account to showcase your skills & expertise to millions of people starting their real estate journey today" <div className="mb-6">
</p> <svg className="w-16 h-16 mx-auto text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
</div> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<h2 className="text-[24px] font-normal text-[#00293d] mb-3">Check Your Email</h2>
<p className="text-sm text-[#00293d]/70 mb-6">
We've sent a verification link to <strong>{email}</strong>. Please check your inbox and click the link to verify your account before logging in.
</p>
<Link
href="/login"
className="inline-block w-full py-4 bg-[#e58625] hover:bg-[#d47a1f] text-[#00293d] font-bold text-sm rounded-[20px] transition-colors text-center"
>
Go to Login
</Link>
<p className="text-xs text-[#00293d]/50 mt-4">
Didn't receive the email? Check your spam folder or contact support.
</p>
</div>
</div>
) : (
<>
{/* Sign Up Heading */}
<div className="text-center mb-6">
<h2 className="text-[30px] font-normal text-[#00293d] mb-3">Sign Up</h2>
<p className="text-sm text-[#00293d] px-4 leading-relaxed">
Sign in or create an account to showcase your skills & expertise to millions of people starting their real estate journey today"
</p>
</div>
{/* User Type Toggle */} {/* User Type Toggle */}
<div className="flex justify-center mb-8"> <div className="flex justify-center mb-8">
<div className="inline-flex bg-[#f0f5fc] rounded-[20px] p-0.5"> <div className="inline-flex bg-[#f0f5fc] rounded-[20px] p-0.5">
<button <button
@@ -276,6 +290,8 @@ export default function SignUpPage() {
<img src="/assets/icons/facebook.svg" alt="Facebook" className="w-6 h-6" /> <img src="/assets/icons/facebook.svg" alt="Facebook" className="w-6 h-6" />
</button> </button>
</div> </div>
</>
)}
</div> </div>
</div> </div>
); );

View File

@@ -25,37 +25,33 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
password: { label: "Password", type: "password" }, password: { label: "Password", type: "password" },
}, },
async authorize(credentials) { async authorize(credentials) {
try { const res = await fetch(
const res = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/auth/login`,
`${process.env.NEXT_PUBLIC_API_URL}/auth/login`, {
{ method: "POST",
method: "POST", headers: { "Content-Type": "application/json" },
headers: { "Content-Type": "application/json" }, body: JSON.stringify({
body: JSON.stringify({ email: credentials?.email,
email: credentials?.email, password: credentials?.password,
password: credentials?.password, }),
}),
}
);
const data = await res.json();
if (res.ok && data.success) {
return {
id: data.data.user.id,
email: data.data.user.email,
name: `${data.data.user.firstName || ""} ${data.data.user.lastName || ""}`.trim(),
role: data.data.user.role,
accessToken: data.data.accessToken,
refreshToken: data.data.refreshToken,
};
} }
);
return null; const data = await res.json();
} catch (error) {
console.error("Auth error:", error); if (res.ok && data.success) {
return null; return {
id: data.data.user.id,
email: data.data.user.email,
name: `${data.data.user.firstName || ""} ${data.data.user.lastName || ""}`.trim(),
role: data.data.user.role,
accessToken: data.data.accessToken,
refreshToken: data.data.refreshToken,
};
} }
// Throw the actual error message from the backend
throw new Error(data.message || "Invalid email or password");
}, },
}), }),
], ],