diff --git a/src/app/(agent)/agent/dashboard/page.tsx b/src/app/(agent)/agent/dashboard/page.tsx
index 2413be4..55fdff0 100644
--- a/src/app/(agent)/agent/dashboard/page.tsx
+++ b/src/app/(agent)/agent/dashboard/page.tsx
@@ -297,11 +297,19 @@ export default function AgentDashboard() {
const handleSubmitVerification = async () => {
setIsSubmittingVerification(true);
try {
- await usersService.submitForVerification();
- // Update local state
+ const result = await usersService.submitForVerification();
+ console.log('Verification submit result:', result);
+ // Update local state immediately
if (agentProfile) {
setAgentProfile({ ...agentProfile, verificationStatus: 'PENDING_REVIEW', verificationNote: null } as AgentProfile);
}
+ // Also re-fetch profile to confirm
+ try {
+ const freshProfile = await agentsService.getProfile();
+ setAgentProfile(freshProfile);
+ } catch {
+ // Local state already updated
+ }
} catch (err: any) {
const data = err?.response?.data;
if (data?.missingFields && Array.isArray(data.missingFields)) {
@@ -328,18 +336,9 @@ export default function AgentDashboard() {
Reason: {agentProfile.verificationNote}
)}
Please update your profile and documents, then resubmit for verification.
-
-
- Edit Profile
-
-
-
+
+ Edit & Resubmit
+
@@ -352,24 +351,15 @@ export default function AgentDashboard() {
)}
- {agentProfile?.verificationStatus === 'NONE' && (
+ {(!agentProfile?.verificationStatus || agentProfile?.verificationStatus === 'NONE') && (
-
Complete your profile and upload verification documents to get verified.
-
-
- Complete Profile
-
-
-
+
Complete your profile to get verified.
+
+ Complete Profile
+
diff --git a/src/app/(agent)/agent/edit/page.tsx b/src/app/(agent)/agent/edit/page.tsx
index 855bf23..386a43e 100644
--- a/src/app/(agent)/agent/edit/page.tsx
+++ b/src/app/(agent)/agent/edit/page.tsx
@@ -7,6 +7,7 @@ import DynamicSection from './components/DynamicSection';
import RepeatableSection, { RepeatableEntryData } from './components/RepeatableSection';
import { profileSectionsService, ProfileSection, AgentTypeSectionsResponse } from '@/services/profile-sections.service';
import { agentsService, AgentProfile, FieldValueInput } from '@/services/agents.service';
+import { usersService } from '@/services/users.service';
import { MobileBackButton } from '@/components/layout/MobileBackButton';
export default function EditProfilePage() {
@@ -38,6 +39,12 @@ export default function EditProfilePage() {
const profile = await agentsService.getMyProfile();
setAgentProfile(profile);
+ // Block editing when verification is under review
+ if (profile.verificationStatus === 'PENDING_REVIEW') {
+ router.push('/agent/dashboard');
+ return;
+ }
+
if (!profile.agentTypeId) {
setError('Your profile does not have an agent type assigned. Please contact support.');
setLoading(false);
@@ -276,28 +283,31 @@ export default function EditProfilePage() {
await agentsService.saveFieldValues(fieldValues);
// Also update main profile fields (phone, email) to keep them in sync
- // This ensures that when the view page checks agentProfile.phone first,
- // it gets the correct (possibly empty) value
const profileUpdates: Partial<{ phone: string | null; email: string | null }> = {};
- // Sync phone field - check dynamic field slugs FIRST, then legacy 'phone'
- // Dynamic fields (phone_number, etc.) are the source of truth from the form
- // 'phone' is a legacy pre-populated key and should only be used as fallback
const phoneFieldSlugs = ['phone_number', 'cell_number', 'office_number', 'phone'];
for (const slug of phoneFieldSlugs) {
const phoneValue = formData[slug];
if (phoneValue !== undefined) {
- // Set to null if empty, otherwise use the value
profileUpdates.phone = phoneValue === '' ? null : (phoneValue as string);
- break; // Use the first found phone field
+ break;
}
}
- // Only update if there are changes to sync
if (Object.keys(profileUpdates).length > 0) {
await agentsService.updateProfile(profileUpdates);
}
+ // Auto-submit for verification (status: NONE or REJECTED → PENDING_REVIEW)
+ const status = agentProfile?.verificationStatus;
+ if (!status || status === 'NONE' || status === 'REJECTED') {
+ try {
+ await usersService.submitForVerification();
+ } catch {
+ // If submit fails (e.g. already pending), still proceed
+ }
+ }
+
router.push('/agent/dashboard');
} catch (err) {
console.error('Failed to save:', err);
@@ -444,7 +454,7 @@ export default function EditProfilePage() {
{isSaving && (
)}
- {isSaving ? 'Saving...' : 'Save'}
+ {isSaving ? 'Submitting...' : 'Submit for Review'}
)}
diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx
index 850dca9..da8b7d4 100644
--- a/src/app/(auth)/login/page.tsx
+++ b/src/app/(auth)/login/page.tsx
@@ -1,13 +1,14 @@
'use client';
import { useState, useEffect } from 'react';
-import { useRouter } from 'next/navigation';
+import { useRouter, useSearchParams } from 'next/navigation';
import { signIn } from 'next-auth/react';
import Link from 'next/link';
import { resetLogoutState } from '@/services/api';
export default function LoginPage() {
const router = useRouter();
+ const searchParams = useSearchParams();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [showPassword, setShowPassword] = useState(false);
@@ -19,7 +20,12 @@ export default function LoginPage() {
useEffect(() => {
localStorage.removeItem('isLoggingOut');
resetLogoutState();
- }, []);
+ // Show error from social login redirect
+ const errorParam = searchParams.get('error');
+ if (errorParam) {
+ setError(errorParam);
+ }
+ }, [searchParams]);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
@@ -90,6 +96,8 @@ export default function LoginPage() {
};
const handleSocialLogin = (provider: 'google' | 'facebook' | 'twitter') => {
+ // Set login mode so backend rejects if user doesn't exist
+ document.cookie = `socialAuthMode=login;path=/;max-age=300;SameSite=Lax`;
signIn(provider, { callbackUrl: '/' });
};
diff --git a/src/app/(auth)/signup/page.tsx b/src/app/(auth)/signup/page.tsx
index 14a6fc5..57bff52 100644
--- a/src/app/(auth)/signup/page.tsx
+++ b/src/app/(auth)/signup/page.tsx
@@ -99,7 +99,8 @@ export default function SignUpPage() {
setError('Please select an agent type before signing up');
return;
}
- // Set cookies with selected role and agent type so server-side auth callback can read them
+ // Set cookies with mode, role and agent type so server-side auth callback can read them
+ document.cookie = `socialAuthMode=signup;path=/;max-age=300;SameSite=Lax`;
document.cookie = `socialAuthRole=${userType};path=/;max-age=300;SameSite=Lax`;
if (userType === 'AGENT' && selectedAgentTypeId) {
document.cookie = `socialAuthAgentTypeId=${selectedAgentTypeId};path=/;max-age=300;SameSite=Lax`;
diff --git a/src/auth.ts b/src/auth.ts
index 25505c2..6f7f57e 100644
--- a/src/auth.ts
+++ b/src/auth.ts
@@ -117,11 +117,13 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
// Read role and agent type from cookies (set by signup page before OAuth redirect)
let role: string | undefined;
let agentTypeId: string | undefined;
+ let mode: string | undefined;
try {
const { cookies } = await import("next/headers");
const cookieStore = await cookies();
role = cookieStore.get("socialAuthRole")?.value;
agentTypeId = cookieStore.get("socialAuthAgentTypeId")?.value;
+ mode = cookieStore.get("socialAuthMode")?.value;
} catch {
// Cookie may not be available
}
@@ -139,6 +141,7 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
avatar: user.image,
role,
agentTypeId,
+ mode: mode || 'signup',
}),
}
);
@@ -150,6 +153,9 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
(user as any).role = data.data.user.role;
(user as any).accessToken = data.data.accessToken;
(user as any).refreshToken = data.data.refreshToken;
+ } else if (!res.ok) {
+ const errorMsg = data?.message || "Social login failed";
+ return `/login?error=${encodeURIComponent(errorMsg)}`;
}
} catch (error) {
console.error("Social auth sync error:", error);