From 9042913e227b3b9ccf3cbd04cd3afb06675065fe Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Tue, 14 Apr 2026 10:11:02 +0530 Subject: [PATCH] feat: add personal tagline support and improve snake_case string formatting in profile data mapping --- src/app/(agent)/agent/dashboard/page.tsx | 13 +++++++- src/app/(user)/user/profile/[id]/page.tsx | 21 +++++++++---- src/components/profile/ExperienceSection.tsx | 25 ++++++++-------- src/utils/profileDataMapper.ts | 31 ++++++++++++++++++-- 4 files changed, 70 insertions(+), 20 deletions(-) diff --git a/src/app/(agent)/agent/dashboard/page.tsx b/src/app/(agent)/agent/dashboard/page.tsx index d2b8d6f..e4a2471 100644 --- a/src/app/(agent)/agent/dashboard/page.tsx +++ b/src/app/(agent)/agent/dashboard/page.tsx @@ -21,7 +21,7 @@ import { connectionRequestsService } from '@/services/connection-requests.servic import { uploadService } from '@/services/upload.service'; import { usersService } from '@/services/users.service'; import { testimonialsService, Testimonial } from '@/services/testimonials.service'; -import { mapFieldValuesToExperience, mapFieldValuesToProfileCard, mapFieldValuesToAvailability, mapFieldValuesToSpecializationFields, mapFieldValuesToContactInfo, mapFieldValuesToWorkEnvironment, ExperienceData, ProfileCardData, AvailabilityData, SpecializationFieldsData, ContactInfoData, WorkEnvironmentData } from '@/utils/profileDataMapper'; +import { mapFieldValuesToExperience, mapFieldValuesToProfileCard, mapFieldValuesToAvailability, mapFieldValuesToSpecializationFields, mapFieldValuesToContactInfo, mapFieldValuesToWorkEnvironment, mapFieldValuesToPersonalTagline, ExperienceData, ProfileCardData, AvailabilityData, SpecializationFieldsData, ContactInfoData, WorkEnvironmentData, PersonalTaglineData } from '@/utils/profileDataMapper'; // Default work environment data const defaultWorkEnvironmentData: WorkEnvironmentData = { @@ -29,6 +29,12 @@ const defaultWorkEnvironmentData: WorkEnvironmentData = { content: '', }; +// Default personal tagline data +const defaultPersonalTaglineData: PersonalTaglineData = { + label: 'Personal Tagline', + content: '', +}; + // Default experience data when no field values are available const defaultExperience: ExperienceData = { years: '-', @@ -82,6 +88,7 @@ export default function AgentDashboard() { const [profileCardData, setProfileCardData] = useState(defaultProfileCardData); const [availabilityData, setAvailabilityData] = useState(defaultAvailabilityData); const [workEnvironmentData, setWorkEnvironmentData] = useState(defaultWorkEnvironmentData); + const [personalTaglineData, setPersonalTaglineData] = useState(defaultPersonalTaglineData); const [specializationFieldsData, setSpecializationFieldsData] = useState(defaultSpecializationFieldsData); const [contactInfoData, setContactInfoData] = useState(defaultContactInfoData); const [loading, setLoading] = useState(true); @@ -157,6 +164,10 @@ export default function AgentDashboard() { const mappedWorkEnv = mapFieldValuesToWorkEnvironment(fieldValuesResponse.fieldValues); setWorkEnvironmentData(mappedWorkEnv); + // Map field values to personal tagline data + const mappedTagline = mapFieldValuesToPersonalTagline(fieldValuesResponse.fieldValues); + setPersonalTaglineData(mappedTagline); + // Map field values to specialization fields data (only fields from "Specialization" section) const mappedSpecializationFields = mapFieldValuesToSpecializationFields(fieldValuesResponse.fieldValues); setSpecializationFieldsData(mappedSpecializationFields); diff --git a/src/app/(user)/user/profile/[id]/page.tsx b/src/app/(user)/user/profile/[id]/page.tsx index 57fa9b1..145d3e2 100644 --- a/src/app/(user)/user/profile/[id]/page.tsx +++ b/src/app/(user)/user/profile/[id]/page.tsx @@ -21,7 +21,7 @@ import { agentsService, AgentProfile, FieldValueResponse } from '@/services/agen import { connectionRequestsService, ConnectionStatus } from '@/services/connection-requests.service'; import { uploadService } from '@/services/upload.service'; import { testimonialsService, Testimonial } from '@/services/testimonials.service'; -import { mapFieldValuesToExperience, mapFieldValuesToSpecializationFields, mapFieldValuesToProfileCard, mapFieldValuesToContactInfo, mapFieldValuesToAvailability, mapFieldValuesToWorkEnvironment, ExperienceData, SpecializationFieldsData, ProfileCardData, ContactInfoData, AvailabilityData, WorkEnvironmentData } from '@/utils/profileDataMapper'; +import { mapFieldValuesToExperience, mapFieldValuesToSpecializationFields, mapFieldValuesToProfileCard, mapFieldValuesToContactInfo, mapFieldValuesToAvailability, mapFieldValuesToWorkEnvironment, mapFieldValuesToPersonalTagline, ExperienceData, SpecializationFieldsData, ProfileCardData, ContactInfoData, AvailabilityData, WorkEnvironmentData, PersonalTaglineData } from '@/utils/profileDataMapper'; // Default work environment data const defaultWorkEnvironmentData: WorkEnvironmentData = { @@ -29,6 +29,12 @@ const defaultWorkEnvironmentData: WorkEnvironmentData = { content: '', }; +// Default personal tagline data +const defaultPersonalTaglineData: PersonalTaglineData = { + label: 'Personal Tagline', + content: '', +}; + // Default experience data when no field values are available const defaultExperience: ExperienceData = { years: '-', @@ -87,6 +93,7 @@ export default function AgentProfileView() { const [contactInfoData, setContactInfoData] = useState(defaultContactInfoData); const [availabilityData, setAvailabilityData] = useState(defaultAvailabilityData); const [workEnvironmentData, setWorkEnvironmentData] = useState(defaultWorkEnvironmentData); + const [personalTaglineData, setPersonalTaglineData] = useState(defaultPersonalTaglineData); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [imageError, setImageError] = useState(false); @@ -150,6 +157,10 @@ export default function AgentProfileView() { const mappedWorkEnv = mapFieldValuesToWorkEnvironment(fieldValuesResponse.fieldValues); setWorkEnvironmentData(mappedWorkEnv); + // Map field values to personal tagline data + const mappedTagline = mapFieldValuesToPersonalTagline(fieldValuesResponse.fieldValues); + setPersonalTaglineData(mappedTagline); + // Map testimonials for TestimonialsSection setTestimonials( testimonialsData.map((t) => ({ @@ -427,18 +438,18 @@ export default function AgentProfileView() { content={

{workEnvironmentData.content}

} /> )} - {testimonials.length > 0 && ( + {personalTaglineData.content && ( } - content={

“{testimonials[0].text.length > 150 ? testimonials[0].text.substring(0, 150) + '...' : testimonials[0].text}”

} + content={

“{personalTaglineData.content.length > 150 ? personalTaglineData.content.substring(0, 150) + '...' : personalTaglineData.content}”

} /> )} diff --git a/src/components/profile/ExperienceSection.tsx b/src/components/profile/ExperienceSection.tsx index 27a9a8e..26e4e68 100644 --- a/src/components/profile/ExperienceSection.tsx +++ b/src/components/profile/ExperienceSection.tsx @@ -17,12 +17,8 @@ export function ExperienceSection({ experience }: ExperienceSectionProps) { const [showAllExpertise, setShowAllExpertise] = useState(false); const [showAllCertifications, setShowAllCertifications] = useState(false); - // Build agency display — append designation if flag is set - const agencyDisplay = experience.agencyName - ? (experience.agencyShowDesignation && experience.agencyDesignation - ? `${experience.agencyName} - ${experience.agencyDesignation}` - : experience.agencyName) - : ''; + // Show agency block whenever name OR designation is filled + const hasAgency = !!(experience.agencyName || experience.agencyDesignation); // Calculate how many more items are hidden const licensingRemaining = experience.licensingAreas.length - INITIAL_DISPLAY_COUNT; @@ -46,15 +42,20 @@ export function ExperienceSection({ experience }: ExperienceSectionProps) {
{/* Left Column */}
- {agencyDisplay && ( + {hasAgency && ( <>

{experience.agencySectionLabel}

-
    -
  • - {agencyDisplay} -
  • -
+ {experience.agencyName && ( +

+ {experience.agencyName} +

+ )} + {experience.agencyDesignation && ( +

+ {experience.agencyDesignation} +

+ )}
{/* Horizontal divider */}
diff --git a/src/utils/profileDataMapper.ts b/src/utils/profileDataMapper.ts index 006581c..a0c15d6 100644 --- a/src/utils/profileDataMapper.ts +++ b/src/utils/profileDataMapper.ts @@ -239,6 +239,23 @@ export function mapFieldValuesToWorkEnvironment(fieldValues: FieldValueResponse[ }; } +// Personal tagline data structure +export interface PersonalTaglineData { + label: string; + content: string; +} + +/** + * Maps field values to personal tagline data (label + content) + */ +export function mapFieldValuesToPersonalTagline(fieldValues: FieldValueResponse[]): PersonalTaglineData { + const field = fieldValues.find(f => f.fieldSlug === 'personal_tagline'); + return { + label: field?.fieldName || 'Personal Tagline', + content: (field?.value as string | undefined)?.trim() || '', + }; +} + // Type-determining values (business hours → Full-time, etc.) const fullTimeKeywords = ['full_time', 'mf_9_5', 'mf_8_6', 'full time', '9-5', '9 am', '9am']; const partTimeKeywords = ['part_time', 'part time']; @@ -264,13 +281,23 @@ export function mapFieldValuesToAvailability(fieldValues: FieldValueResponse[]): return { type: '', schedule: [], label }; } + // Helper to format snake_case strings to Title Case (for unresolved raw values) + const formatIfSnakeCase = (s: string): string => { + const trimmed = s.trim(); + // If it looks like a snake_case key (e.g. "mf_9_5"), format it + if (/^[a-z0-9]+(_[a-z0-9]+)+$/i.test(trimmed)) { + return trimmed.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()); + } + return trimmed; + }; + // Prefer backend-resolved labels, fall back to raw value with snake_case formatting const resolvedLabels = rawValues.map((val, i) => { const fromBackend = labelValues[i]; if (fromBackend && typeof fromBackend === 'string' && fromBackend.trim()) { - return fromBackend.trim(); + return formatIfSnakeCase(fromBackend); } - return val.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()); + return formatIfSnakeCase(val); }); // Deduplicate by normalized comparison (case/whitespace insensitive)