From 7e8576c0068e8137116b39b7a40afded4c633ebd Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Mon, 9 Feb 2026 01:42:26 +0530 Subject: [PATCH] feat: Add cache-busting to avatar image URLs and implement show more/less functionality for certifications. --- src/app/(agent)/agent/edit/page.tsx | 22 ++++++++++ src/app/(user)/user/profile/[id]/page.tsx | 9 +++- src/app/(user)/user/profiles/page.tsx | 11 ++++- src/components/profile/ExperienceSection.tsx | 44 +++++++++++++++----- 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/src/app/(agent)/agent/edit/page.tsx b/src/app/(agent)/agent/edit/page.tsx index 9ed49a0..9347d7b 100644 --- a/src/app/(agent)/agent/edit/page.tsx +++ b/src/app/(agent)/agent/edit/page.tsx @@ -269,6 +269,28 @@ export default function EditProfilePage() { // Save field values to API 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 multiple possible field slugs + // The dynamic fields might use different slugs for phone + const phoneFieldSlugs = ['phone', 'phone_number', 'cell_number', 'office_number']; + 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 + } + } + + // Only update if there are changes to sync + if (Object.keys(profileUpdates).length > 0) { + await agentsService.updateProfile(profileUpdates); + } + router.push('/agent/dashboard'); } catch (err) { console.error('Failed to save:', err); diff --git a/src/app/(user)/user/profile/[id]/page.tsx b/src/app/(user)/user/profile/[id]/page.tsx index 0ad6494..128681e 100644 --- a/src/app/(user)/user/profile/[id]/page.tsx +++ b/src/app/(user)/user/profile/[id]/page.tsx @@ -158,7 +158,14 @@ export default function AgentProfileView() { if (profile.avatar && isS3Key(profile.avatar)) { try { const presignedUrl = await uploadService.getPresignedDownloadUrl(profile.avatar); - setAvatarUrl(presignedUrl); + // Add cache-busting parameter to force browser to fetch fresh image + // This prevents showing old cached image when avatar is updated + const profileWithTimestamp = profile as unknown as { updatedAt?: string }; + const cacheBuster = profileWithTimestamp.updatedAt + ? new Date(profileWithTimestamp.updatedAt).getTime() + : Date.now(); + const urlWithCacheBuster = `${presignedUrl}&_t=${cacheBuster}`; + setAvatarUrl(urlWithCacheBuster); } catch (avatarErr) { console.error('Failed to get avatar URL:', avatarErr); // Don't fail the whole page, just use default image diff --git a/src/app/(user)/user/profiles/page.tsx b/src/app/(user)/user/profiles/page.tsx index 25feea6..a103dd7 100644 --- a/src/app/(user)/user/profiles/page.tsx +++ b/src/app/(user)/user/profiles/page.tsx @@ -73,7 +73,14 @@ function ProfileCard({ profile }: ProfileCardProps) { if (profile.avatar && !profile.avatar.startsWith('http') && !profile.avatar.startsWith('/')) { try { const presignedUrl = await uploadService.getPresignedDownloadUrl(profile.avatar); - setAvatarUrl(presignedUrl); + // Add cache-busting parameter to force browser to fetch fresh image + // This prevents showing old cached image when avatar is updated + const profileWithTimestamp = profile as unknown as { updatedAt?: string }; + const cacheBuster = profileWithTimestamp.updatedAt + ? new Date(profileWithTimestamp.updatedAt).getTime() + : Date.now(); + const urlWithCacheBuster = `${presignedUrl}&_t=${cacheBuster}`; + setAvatarUrl(urlWithCacheBuster); } catch (error) { console.error('Failed to get avatar URL:', error); } @@ -82,7 +89,7 @@ function ProfileCard({ profile }: ProfileCardProps) { } }; fetchAvatarUrl(); - }, [profile.avatar]); + }, [profile.avatar, profile]); const getProfileImageUrl = () => { if (avatarUrl) return avatarUrl; diff --git a/src/components/profile/ExperienceSection.tsx b/src/components/profile/ExperienceSection.tsx index cb026ea..af6e716 100644 --- a/src/components/profile/ExperienceSection.tsx +++ b/src/components/profile/ExperienceSection.tsx @@ -17,14 +17,17 @@ interface ExperienceSectionProps { const INITIAL_DISPLAY_COUNT = 6; const EXPERTISE_INITIAL_COUNT = 4; +const CERTIFICATIONS_INITIAL_COUNT = 2; export function ExperienceSection({ experience }: ExperienceSectionProps) { const [showAllLicensing, setShowAllLicensing] = useState(false); const [showAllExpertise, setShowAllExpertise] = useState(false); + const [showAllCertifications, setShowAllCertifications] = useState(false); // Calculate how many more items are hidden const licensingRemaining = experience.licensingAreas.length - INITIAL_DISPLAY_COUNT; const expertiseRemaining = experience.expertiseYears.length - EXPERTISE_INITIAL_COUNT; + const certificationsRemaining = experience.certifications.length - CERTIFICATIONS_INITIAL_COUNT; // Get displayed items const displayedLicensing = showAllLicensing @@ -33,6 +36,9 @@ export function ExperienceSection({ experience }: ExperienceSectionProps) { const displayedExpertise = showAllExpertise ? experience.expertiseYears : experience.expertiseYears.slice(0, EXPERTISE_INITIAL_COUNT); + const displayedCertifications = showAllCertifications + ? experience.certifications + : experience.certifications.slice(0, CERTIFICATIONS_INITIAL_COUNT); return (
@@ -133,16 +139,34 @@ export function ExperienceSection({ experience }: ExperienceSectionProps) {

Certifications

{experience.certifications.length > 0 ? ( -
    - {experience.certifications.map((cert, idx) => ( -
  • - {cert.name} - {cert.org && ( -

    {cert.org}

    - )} -
  • - ))} -
+
+
    + {displayedCertifications.map((cert, idx) => ( +
  • + {cert.name} + {cert.org && ( +

    {cert.org}

    + )} +
  • + ))} +
+ {!showAllCertifications && certificationsRemaining > 0 && ( + + )} + {showAllCertifications && experience.certifications.length > CERTIFICATIONS_INITIAL_COUNT && ( + + )} +
) : ( No certifications added )}