fix
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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: '/' });
|
||||
};
|
||||
|
||||
|
||||
@@ -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`;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user