From 2337f5646f7c0705c6245e599750b58557f53e94 Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Mon, 20 Apr 2026 14:07:33 +0530 Subject: [PATCH] feat: implement email change functionality with verification modal in profile settings --- .../settings/ProfileSettingsForm.tsx | 123 +++++++++++++++++- src/services/auth.service.ts | 13 ++ 2 files changed, 130 insertions(+), 6 deletions(-) diff --git a/src/components/settings/ProfileSettingsForm.tsx b/src/components/settings/ProfileSettingsForm.tsx index a18a54e..de2f39f 100644 --- a/src/components/settings/ProfileSettingsForm.tsx +++ b/src/components/settings/ProfileSettingsForm.tsx @@ -6,6 +6,7 @@ import { useSession, signIn } from 'next-auth/react'; import { uploadService } from '@/services/upload.service'; import { agentsService } from '@/services/agents.service'; import { usersService } from '@/services/users.service'; +import { authService, AuthService } from '@/services/auth.service'; interface ProfileSettingsFormProps { initialData?: { @@ -50,6 +51,32 @@ export function ProfileSettingsForm({ const [isSaving, setIsSaving] = useState(false); const [error, setError] = useState(null); const [successMessage, setSuccessMessage] = useState(null); + const [isEmailModalOpen, setIsEmailModalOpen] = useState(false); + const [emailModalData, setEmailModalData] = useState({ newEmail: '', password: '' }); + const [emailModalError, setEmailModalError] = useState(null); + const [emailModalSubmitting, setEmailModalSubmitting] = useState(false); + + const handleRequestEmailChange = async () => { + setEmailModalError(null); + if (!emailModalData.newEmail.trim() || !emailModalData.password) { + setEmailModalError('Please enter a new email and your current password'); + return; + } + setEmailModalSubmitting(true); + try { + const res = await authService.requestEmailChange({ + newEmail: emailModalData.newEmail.trim(), + password: emailModalData.password, + }); + setSuccessMessage(res.data?.message || 'Verification email sent. Please check your new inbox.'); + setIsEmailModalOpen(false); + setEmailModalData({ newEmail: '', password: '' }); + } catch (err) { + setEmailModalError(AuthService.getErrorMessage(err)); + } finally { + setEmailModalSubmitting(false); + } + }; // Reset avatar loaded state when URL changes (e.g., after upload) useEffect(() => { setAvatarLoaded(false); @@ -462,12 +489,25 @@ export function ProfileSettingsForm({ - +
+ + +
+ + {/* Change Email Modal */} + {isEmailModalOpen && ( +
+
!emailModalSubmitting && setIsEmailModalOpen(false)} + /> +
+
+

Change Email Address

+ +
+
+

+ A verification link will be sent to your new email. Your email changes only after you click the link. +

+
+ + setEmailModalData({ ...emailModalData, newEmail: e.target.value })} + placeholder="new@example.com" + autoComplete="off" + className="w-full h-[44px] px-4 border border-[#00293D]/20 rounded-[10px] text-[14px] font-serif text-[#00293D] focus:outline-none focus:border-[#E58625]" + /> +
+
+ + setEmailModalData({ ...emailModalData, password: e.target.value })} + placeholder="Enter your current password" + autoComplete="current-password" + className="w-full h-[44px] px-4 border border-[#00293D]/20 rounded-[10px] text-[14px] font-serif text-[#00293D] focus:outline-none focus:border-[#E58625]" + /> +
+ {emailModalError && ( +
+

{emailModalError}

+
+ )} +
+
+ + +
+
+
+ )}
); } diff --git a/src/services/auth.service.ts b/src/services/auth.service.ts index e5e93be..0589d51 100644 --- a/src/services/auth.service.ts +++ b/src/services/auth.service.ts @@ -44,6 +44,11 @@ export interface VerifyEmailRequest { token: string; } +export interface ChangeEmailRequest { + newEmail: string; + password: string; +} + export interface MessageResponse { message: string; } @@ -99,6 +104,14 @@ class AuthService { return response.data; } + async requestEmailChange(data: ChangeEmailRequest): Promise> { + const response = await api.post>( + `${this.basePath}/change-email`, + data + ); + return response.data; + } + async getCurrentUser(): Promise> { const response = await api.get>(`${this.basePath}/me`); return response.data;