feat: Implement dynamic city and state retrieval and display for profiles, utilizing new data mapping and updated UI logic.
This commit is contained in:
@@ -81,6 +81,8 @@ const defaultProfileCardData: ProfileCardData = {
|
|||||||
bio: '',
|
bio: '',
|
||||||
expertise: [],
|
expertise: [],
|
||||||
serviceAreas: [],
|
serviceAreas: [],
|
||||||
|
city: null,
|
||||||
|
state: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Default availability data when no field values are available
|
// Default availability data when no field values are available
|
||||||
@@ -316,7 +318,11 @@ export default function AgentDashboard() {
|
|||||||
lastName={agentProfile.lastName}
|
lastName={agentProfile.lastName}
|
||||||
isVerified={agentProfile.isVerified}
|
isVerified={agentProfile.isVerified}
|
||||||
title={agentProfile.agentType?.name || 'Real Estate Agent'}
|
title={agentProfile.agentType?.name || 'Real Estate Agent'}
|
||||||
location={profileCardData.serviceAreas?.[0] || (agentProfile as unknown as { city?: string }).city || 'United States'}
|
location={
|
||||||
|
profileCardData.city && profileCardData.state
|
||||||
|
? `${profileCardData.city}, ${profileCardData.state}`
|
||||||
|
: profileCardData.city || profileCardData.state || profileCardData.serviceAreas?.[0] || 'United States'
|
||||||
|
}
|
||||||
memberSince={formatMemberSince((agentProfile as unknown as { createdAt?: string }).createdAt)}
|
memberSince={formatMemberSince((agentProfile as unknown as { createdAt?: string }).createdAt)}
|
||||||
bio={profileCardData.bio || agentProfile.bio || ''}
|
bio={profileCardData.bio || agentProfile.bio || ''}
|
||||||
expertise={profileCardData.expertise}
|
expertise={profileCardData.expertise}
|
||||||
|
|||||||
@@ -101,22 +101,63 @@ function ProfileCard({ profile }: ProfileCardProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get location string - prefer city/state/country over serviceAreas
|
// Get location string - check dynamic field values first, then fallback to legacy columns
|
||||||
const getLocation = () => {
|
const getLocation = () => {
|
||||||
if (profile.city && profile.state) {
|
let cityValue: string | null = null;
|
||||||
return `${profile.city}, ${profile.state}`;
|
let stateValue: string | null = null;
|
||||||
|
|
||||||
|
// Helper to format snake_case to Title Case
|
||||||
|
const formatValue = (v: string) => v.split('_').map(w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(' ');
|
||||||
|
|
||||||
|
// First, check fieldValues for state and city (dynamic profile fields)
|
||||||
|
if (profile.fieldValues && profile.fieldValues.length > 0) {
|
||||||
|
const stateField = profile.fieldValues.find(fv => fv.field.slug === 'state');
|
||||||
|
const cityField = profile.fieldValues.find(fv => fv.field.slug === 'city');
|
||||||
|
|
||||||
|
if (stateField && stateField.jsonValue) {
|
||||||
|
const value = stateField.jsonValue;
|
||||||
|
if (Array.isArray(value) && value.length > 0) {
|
||||||
|
// For multiselect, join all selected values
|
||||||
|
stateValue = value.map(v => formatValue(String(v))).join(', ');
|
||||||
|
} else if (typeof value === 'string' && value.trim()) {
|
||||||
|
stateValue = formatValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cityField && cityField.jsonValue) {
|
||||||
|
const value = cityField.jsonValue;
|
||||||
|
if (Array.isArray(value) && value.length > 0) {
|
||||||
|
// For multiselect, join all selected values
|
||||||
|
cityValue = value.map(v => formatValue(String(v))).join(', ');
|
||||||
|
} else if (typeof value === 'string' && value.trim()) {
|
||||||
|
cityValue = formatValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (profile.city && profile.country) {
|
|
||||||
return `${profile.city}, ${profile.country}`;
|
// Fallback to legacy profile columns if dynamic fields not found
|
||||||
|
if (!cityValue && profile.city) {
|
||||||
|
cityValue = profile.city;
|
||||||
}
|
}
|
||||||
if (profile.state && profile.country) {
|
if (!stateValue && profile.state) {
|
||||||
return `${profile.state}, ${profile.country}`;
|
stateValue = profile.state;
|
||||||
}
|
}
|
||||||
if (profile.city) {
|
|
||||||
return profile.city;
|
// Build location string
|
||||||
|
if (cityValue && stateValue) {
|
||||||
|
return `${cityValue}, ${stateValue}`;
|
||||||
}
|
}
|
||||||
if (profile.state) {
|
if (cityValue && profile.country) {
|
||||||
return profile.state;
|
return `${cityValue}, ${profile.country}`;
|
||||||
|
}
|
||||||
|
if (stateValue && profile.country) {
|
||||||
|
return `${stateValue}, ${profile.country}`;
|
||||||
|
}
|
||||||
|
if (cityValue) {
|
||||||
|
return cityValue;
|
||||||
|
}
|
||||||
|
if (stateValue) {
|
||||||
|
return stateValue;
|
||||||
}
|
}
|
||||||
if (profile.country) {
|
if (profile.country) {
|
||||||
return profile.country;
|
return profile.country;
|
||||||
@@ -131,9 +172,17 @@ function ProfileCard({ profile }: ProfileCardProps) {
|
|||||||
const getExpertiseTags = (): string[] => {
|
const getExpertiseTags = (): string[] => {
|
||||||
const tags: string[] = [];
|
const tags: string[] = [];
|
||||||
|
|
||||||
|
// Fields to exclude from tags (they're displayed elsewhere, e.g., state/city shown in location)
|
||||||
|
const excludedFieldSlugs = ['state', 'city', 'description'];
|
||||||
|
|
||||||
// Add from fieldValues (dynamic profile fields like client_specialization, property_type, loan_type)
|
// Add from fieldValues (dynamic profile fields like client_specialization, property_type, loan_type)
|
||||||
if (profile.fieldValues && profile.fieldValues.length > 0) {
|
if (profile.fieldValues && profile.fieldValues.length > 0) {
|
||||||
profile.fieldValues.forEach((fv) => {
|
profile.fieldValues.forEach((fv) => {
|
||||||
|
// Skip excluded fields
|
||||||
|
if (excludedFieldSlugs.includes(fv.field.slug)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const value = fv.jsonValue;
|
const value = fv.jsonValue;
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
// For multi-select fields, add all selected values
|
// For multi-select fields, add all selected values
|
||||||
|
|||||||
@@ -130,6 +130,8 @@ export interface ProfileCardData {
|
|||||||
bio: string;
|
bio: string;
|
||||||
expertise: string[];
|
expertise: string[];
|
||||||
serviceAreas: string[];
|
serviceAreas: string[];
|
||||||
|
city: string | null;
|
||||||
|
state: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamic field data structure for SpecializationSection component
|
// Dynamic field data structure for SpecializationSection component
|
||||||
@@ -206,7 +208,31 @@ export function mapFieldValuesToAvailability(fieldValues: FieldValueResponse[]):
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps field values to profile card data (bio, expertise, service areas)
|
* Helper to format snake_case values to Title Case
|
||||||
|
*/
|
||||||
|
function formatSnakeCaseToTitleCase(value: string): string {
|
||||||
|
return value
|
||||||
|
.split('_')
|
||||||
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
||||||
|
.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract all values from a field that may be an array (multiselect) or string
|
||||||
|
* Returns formatted values joined by comma, or null if empty
|
||||||
|
*/
|
||||||
|
function extractAllValues(value: unknown): string | null {
|
||||||
|
if (Array.isArray(value) && value.length > 0) {
|
||||||
|
return value.map(v => formatSnakeCaseToTitleCase(String(v))).join(', ');
|
||||||
|
}
|
||||||
|
if (typeof value === 'string' && value.trim()) {
|
||||||
|
return formatSnakeCaseToTitleCase(value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps field values to profile card data (bio, expertise, service areas, location)
|
||||||
*/
|
*/
|
||||||
export function mapFieldValuesToProfileCard(fieldValues: FieldValueResponse[]): ProfileCardData {
|
export function mapFieldValuesToProfileCard(fieldValues: FieldValueResponse[]): ProfileCardData {
|
||||||
// Get bio/description from various possible fields
|
// Get bio/description from various possible fields
|
||||||
@@ -226,10 +252,16 @@ export function mapFieldValuesToProfileCard(fieldValues: FieldValueResponse[]):
|
|||||||
const licensedAreas = getFieldValue(fieldValues, 'licensed_areas') as string[] | undefined;
|
const licensedAreas = getFieldValue(fieldValues, 'licensed_areas') as string[] | undefined;
|
||||||
const coverageAreas = getFieldValue(fieldValues, 'coverage_areas') as string[] | undefined;
|
const coverageAreas = getFieldValue(fieldValues, 'coverage_areas') as string[] | undefined;
|
||||||
|
|
||||||
|
// Get city and state from dynamic fields (multiselect fields)
|
||||||
|
const cityValue = getFieldValue(fieldValues, 'city');
|
||||||
|
const stateValue = getFieldValue(fieldValues, 'state');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bio: description || descrption || biography || bio || '',
|
bio: description || descrption || biography || bio || '',
|
||||||
expertise: aboutMeExpertise || expertiseAreas || specializations || areasOfExpertise || [],
|
expertise: aboutMeExpertise || expertiseAreas || specializations || areasOfExpertise || [],
|
||||||
serviceAreas: serviceAreas || licensedAreas || coverageAreas || [],
|
serviceAreas: serviceAreas || licensedAreas || coverageAreas || [],
|
||||||
|
city: extractAllValues(cityValue),
|
||||||
|
state: extractAllValues(stateValue),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user