This commit is contained in:
pradeepkumar
2026-03-31 23:23:16 +05:30
parent f7f308af84
commit 719404b663
5 changed files with 55 additions and 40 deletions

View File

@@ -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() {
<p className="font-serif text-[13px] text-red-700 mt-1">Reason: {agentProfile.verificationNote}</p>
)}
<p className="font-serif text-[13px] text-red-600 mt-2">Please update your profile and documents, then resubmit for verification.</p>
<div className="flex gap-2 mt-2">
<Link href="/agent/edit" className="inline-block px-4 py-1.5 border border-[#e58625] text-[#e58625] rounded-[10px] font-serif text-[13px] hover:bg-[#e58625]/5 transition-colors">
Edit Profile
</Link>
<button
onClick={handleSubmitVerification}
disabled={isSubmittingVerification}
className="px-4 py-1.5 bg-[#e58625] text-white rounded-[10px] font-serif text-[13px] hover:bg-[#d47920] transition-colors disabled:opacity-50"
>
{isSubmittingVerification ? 'Submitting...' : 'Submit for Review'}
</button>
</div>
<Link href="/agent/edit" className="inline-block mt-2 px-4 py-1.5 bg-[#e58625] text-white rounded-[10px] font-serif text-[13px] hover:bg-[#d47920] transition-colors">
Edit & Resubmit
</Link>
</div>
</div>
</div>
@@ -352,24 +351,15 @@ export default function AgentDashboard() {
</div>
</div>
)}
{agentProfile?.verificationStatus === 'NONE' && (
{(!agentProfile?.verificationStatus || agentProfile?.verificationStatus === 'NONE') && (
<div className="bg-blue-50 border border-blue-200 rounded-[15px] p-4">
<div className="flex items-center gap-3">
<Image src="/assets/icons/caution-icon.svg" alt="Info" width={20} height={20} className="flex-shrink-0" />
<div className="flex-1">
<p className="font-fractul font-bold text-[14px] text-blue-800">Complete your profile and upload verification documents to get verified.</p>
<div className="flex gap-2 mt-2">
<Link href="/agent/edit" className="inline-block px-4 py-1.5 border border-[#e58625] text-[#e58625] rounded-[10px] font-serif text-[13px] hover:bg-[#e58625]/5 transition-colors">
Complete Profile
</Link>
<button
onClick={handleSubmitVerification}
disabled={isSubmittingVerification}
className="px-4 py-1.5 bg-[#e58625] text-white rounded-[10px] font-serif text-[13px] hover:bg-[#d47920] transition-colors disabled:opacity-50"
>
{isSubmittingVerification ? 'Submitting...' : 'Submit for Review'}
</button>
</div>
<p className="font-fractul font-bold text-[14px] text-blue-800">Complete your profile to get verified.</p>
<Link href="/agent/edit" className="inline-block mt-2 px-4 py-1.5 bg-[#e58625] text-white rounded-[10px] font-serif text-[13px] hover:bg-[#d47920] transition-colors">
Complete Profile
</Link>
</div>
</div>
</div>

View File

@@ -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 && (
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
)}
{isSaving ? 'Saving...' : 'Save'}
{isSaving ? 'Submitting...' : 'Submit for Review'}
</button>
</div>
)}

View File

@@ -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: '/' });
};

View File

@@ -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`;

View File

@@ -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);