diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx
index fa1fca2..c5c409a 100644
--- a/src/app/(auth)/login/page.tsx
+++ b/src/app/(auth)/login/page.tsx
@@ -8,6 +8,7 @@ import { Eye, EyeOff } from 'lucide-react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { loginSchema, LoginFormData } from '../../lib/validationSchemas';
+import { FormError, FieldError } from '../../../components/forms/FormError';
export default function LoginPage() {
const [isLoading, setIsLoading] = useState(false);
@@ -99,9 +100,7 @@ export default function LoginPage() {
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-cyan-500 focus:border-transparent outline-none transition-all"
{...register('email')}
/>
- {errors.email && (
-
{errors.email.message}
- )}
+
@@ -123,9 +122,7 @@ export default function LoginPage() {
{showPassword ? : }
- {errors.password && (
- {errors.password.message}
- )}
+
@@ -137,15 +134,7 @@ export default function LoginPage() {
- {apiError && (
-
- {apiError}
-
- )}
+
{successMessage && (
- {errors.name && (
- {errors.name.message}
- )}
+
@@ -114,9 +113,7 @@ export default function SignupPage() {
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-cyan-500 focus:border-transparent outline-none transition-all"
{...register('email')}
/>
- {errors.email && (
-
{errors.email.message}
- )}
+
@@ -138,20 +135,10 @@ export default function SignupPage() {
{showPassword ? : }
- {errors.password && (
- {errors.password.message}
- )}
+
- {apiError && (
-
- {apiError}
-
- )}
+
{successMessage && (
{
label: string;
@@ -69,15 +70,7 @@ export const FormInput = forwardRef(
)}
- {error && (
-
- {error}
-
- )}
+
);
}
diff --git a/src/app/components/profile/ProfileEditForm.tsx b/src/app/components/profile/ProfileEditForm.tsx
index a80065d..fcb9ca1 100644
--- a/src/app/components/profile/ProfileEditForm.tsx
+++ b/src/app/components/profile/ProfileEditForm.tsx
@@ -7,6 +7,7 @@ import toast from 'react-hot-toast';
import ImageUploader from '@/components/shared/ImageUploader';
import PreferencesSection from '@/components/profile/PreferencesSection';
import { useProfileUpdate } from '@/app/hooks/useProfileUpdate';
+import { FieldError } from '@/components/forms/FormError';
const profileSchema = z.object({
firstName: z.string().min(2, 'First name must be at least 2 characters'),
@@ -77,9 +78,7 @@ export default function ProfileEditForm() {
{...register('firstName')}
className="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
- {errors.firstName && (
- {errors.firstName.message}
- )}
+
@@ -91,9 +90,7 @@ export default function ProfileEditForm() {
{...register('lastName')}
className="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
- {errors.lastName && (
-
{errors.lastName.message}
- )}
+
@@ -106,9 +103,7 @@ export default function ProfileEditForm() {
{...register('email')}
className="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
- {errors.email && (
- {errors.email.message}
- )}
+
@@ -120,9 +115,7 @@ export default function ProfileEditForm() {
rows={4}
className="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
- {errors.bio && (
-
{errors.bio.message}
- )}
+
@@ -150,9 +143,7 @@ export default function ProfileEditForm() {
{...register('website')}
className="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
- {errors.website && (
-
{errors.website.message}
- )}
+
diff --git a/src/components/forms/FormError.tsx b/src/components/forms/FormError.tsx
new file mode 100644
index 0000000..8715a21
--- /dev/null
+++ b/src/components/forms/FormError.tsx
@@ -0,0 +1,71 @@
+'use client';
+
+import { motion } from 'framer-motion';
+import { AlertCircle } from 'lucide-react';
+import { useEffect, useRef } from 'react';
+
+// --- GLOBAL FORM ERROR (For Backend / API Errors) ---
+interface FormErrorProps {
+ error?: string | string[] | null;
+ className?: string;
+ id?: string;
+}
+
+export function FormError({ error, className = '', id }: FormErrorProps) {
+ const errorRef = useRef
(null);
+
+ useEffect(() => {
+ if (error && errorRef.current) {
+ errorRef.current.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ }
+ }, [error]);
+
+ if (!error) return null;
+
+ const errors = Array.isArray(error) ? error : [error];
+
+ return (
+
+
+
+ {errors.map((err, index) => (
+
+ {err}
+
+ ))}
+
+
+ );
+}
+
+// --- INLINE FIELD ERROR (For Client Form Validation) ---
+interface FieldErrorProps {
+ error?: string;
+ id?: string;
+}
+
+export function FieldError({ error, id }: FieldErrorProps) {
+ if (!error) return null;
+
+ return (
+
+ {error}
+
+ );
+}
\ No newline at end of file