diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx index 0e80a9c..588c871 100644 --- a/app/(auth)/login/page.tsx +++ b/app/(auth)/login/page.tsx @@ -1,6 +1,6 @@ /** * @file app/(auth)/login/page.tsx - * @description Client component rendering the login page, handling form submission, authentication requests, error messaging, and redirection. + * @description Client component rendering the login page, handling form submission, authentication requests, error messaging, autocomplete, and redirection. */ "use client"; @@ -11,11 +11,7 @@ import Link from "next/link"; import Image from "next/image"; import { loginAsGuest, loginUser } from "@/lib/services/auth.service"; -/** - * Renders the user login interface and manages authentication form state. - * - * @returns {JSX.Element} The rendered login page component. - */ +/** Renders the user login interface and manages authentication form state. */ export default function LoginPage() { const router = useRouter(); const [error, setError] = useState(null); @@ -23,12 +19,15 @@ export default function LoginPage() { "credentials" | "guest" | null >(null); - /** - * Form submit handler extracting credentials from FormData and delegating to handleSignIn. - * - * @param {React.SubmitEvent} e - The form submission event. - */ - const handleSubmit = async (e: React.SubmitEvent) => { + /** Clears active error state when user modifies input fields. */ + const handleInputChange = () => { + if (error) { + setError(null); + } + }; + + /** Form submit handler extracting credentials from FormData and delegating to handleSignIn. */ + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget); const email = formData.get("email") as string; @@ -36,10 +35,7 @@ export default function LoginPage() { await handleSignIn(email, password, "credentials"); }; - /** - * Authenticates the user with provided credentials and redirects upon success. - * - */ + /** Authenticates the user with provided credentials and redirects upon success. */ const handleSignIn = async ( email: string, password: string, @@ -58,11 +54,7 @@ export default function LoginPage() { } }; - /** - * Triggers secure guest authentication via the backend service. - * - * @async - */ + /** Triggers secure guest authentication via the backend service. */ const handleGuestLogin = async () => { setError(null); setLoadingType("guest"); @@ -106,7 +98,11 @@ export default function LoginPage() { )} {/* Form */} -
+
@@ -139,6 +136,7 @@ export default function LoginPage() { required placeholder="•••••••••••••" maxLength={72} + autoComplete="current-password" className="w-full bg-neutral-900 border border-neutral-800 rounded-lg px-3 py-2 text-foreground placeholder-neutral-500 outline-none focus:border-accent transition-colors text-sm" /> @@ -148,7 +146,7 @@ export default function LoginPage() { disabled={loadingType !== null} className="w-full bg-accent hover:opacity-90 transition-opacity text-white font-medium py-2.5 rounded-lg text-sm disabled:opacity-50 mt-2 cursor-pointer" > - {loadingType === "credentials" ? "Signing in..." : "Sign In"}{" "} + {loadingType === "credentials" ? "Signing in..." : "Sign In"}
diff --git a/app/(auth)/register/page.tsx b/app/(auth)/register/page.tsx index 26e860f..4c7a59d 100644 --- a/app/(auth)/register/page.tsx +++ b/app/(auth)/register/page.tsx @@ -1,6 +1,6 @@ /** * @file app/(auth)/register/page.tsx - * @description Client component rendering the registration page, handling form submissions, account creation logic, error handling, and navigation. + * @description Client component rendering the registration page, handling form submissions, client-side validation, error handling, autocomplete, and navigation. */ "use client"; @@ -11,31 +11,35 @@ import Link from "next/link"; import Image from "next/image"; import { registerUser } from "@/lib/services/auth.service"; -/** - * Renders the user registration interface and manages sign-up form state. - * - * @returns {JSX.Element} The rendered registration page component. - */ +/** Renders the user registration interface and manages sign-up form state. */ export default function RegisterPage() { const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const router = useRouter(); - /** - * Handles user registration form submission, validates form data via auth service, - * and navigates to summary page on successful registration. - * - * @param {React.SubmitEvent} event - The form submission event. - * @returns {Promise} - */ - async function handleSubmit(event: React.SubmitEvent) { + /** Clears active error state when user modifies input fields. */ + const handleInputChange = () => { + if (error) { + setError(null); + } + }; + + /** Handles user registration form submission, validates form data via auth service, and navigates to summary page on successful registration. */ + async function handleSubmit(event: React.FormEvent) { event.preventDefault(); setError(null); - setLoading(true); const formData = new FormData(event.currentTarget); const payload = Object.fromEntries(formData.entries()); + // Client-side password matching validation + if (payload.password !== payload.confirmPassword) { + setError("Passwords do not match."); + return; + } + + setLoading(true); + const result = await registerUser(payload); if (result.error) { @@ -75,7 +79,11 @@ export default function RegisterPage() { )} {/* Form */} -
+
@@ -108,6 +117,7 @@ export default function RegisterPage() { required placeholder="name@example.com" maxLength={255} + autoComplete="email" className="w-full bg-neutral-900 border border-neutral-800 rounded-lg px-3 py-2 text-foreground placeholder-neutral-500 outline-none focus:border-accent transition-colors text-sm" /> @@ -126,12 +136,14 @@ export default function RegisterPage() { required placeholder="•••••••••••••" maxLength={72} + autoComplete="new-password" className="w-full bg-neutral-900 border border-neutral-800 rounded-lg px-3 py-2 text-foreground placeholder-neutral-500 outline-none focus:border-accent transition-colors text-sm" /> +