feat: implement dynamic work environment section and improve availability data mapping with backend-resolved labels
This commit is contained in:
@@ -219,60 +219,83 @@ export interface SpecializationFieldsData {
|
||||
export interface AvailabilityData {
|
||||
type: string;
|
||||
schedule: string[];
|
||||
label: string;
|
||||
}
|
||||
|
||||
// Map availability option values to human-readable labels
|
||||
const availabilityLabels: Record<string, string> = {
|
||||
'mf_9_5': 'Monday - Friday, 9 AM - 5 PM',
|
||||
'mf_8_6': 'Monday - Friday, 8 AM - 6 PM',
|
||||
'weekends': 'Weekends',
|
||||
'evenings': 'Evenings',
|
||||
'flexible': 'Flexible Schedule',
|
||||
'full_time': 'Full-time',
|
||||
'part_time': 'Part-time',
|
||||
'24_7': '24/7 Available',
|
||||
'by_appointment': 'By Appointment Only',
|
||||
'monday': 'Monday',
|
||||
'tuesday': 'Tuesday',
|
||||
'wednesday': 'Wednesday',
|
||||
'thursday': 'Thursday',
|
||||
'friday': 'Friday',
|
||||
'saturday': 'Saturday',
|
||||
'sunday': 'Sunday',
|
||||
};
|
||||
// Work environment data structure
|
||||
export interface WorkEnvironmentData {
|
||||
label: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps field values to work environment data (label + content)
|
||||
*/
|
||||
export function mapFieldValuesToWorkEnvironment(fieldValues: FieldValueResponse[]): WorkEnvironmentData {
|
||||
const field = fieldValues.find(f => f.fieldSlug === 'preferred_work_environment');
|
||||
return {
|
||||
label: field?.fieldName || 'Preferred Work Environment',
|
||||
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'];
|
||||
const flexibleKeywords = ['flexible'];
|
||||
|
||||
function matchesKeyword(value: string, keywords: string[]): boolean {
|
||||
const normalized = value.toLowerCase();
|
||||
return keywords.some(kw => normalized.includes(kw));
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps field values to availability data
|
||||
* Uses backend-resolved `valueLabel` and deduplicates by normalized label.
|
||||
*/
|
||||
export function mapFieldValuesToAvailability(fieldValues: FieldValueResponse[]): AvailabilityData {
|
||||
const availabilityValues = getFieldValue(fieldValues, 'availability') as string[] | undefined;
|
||||
const field = fieldValues.find(f => f.fieldSlug === 'availability');
|
||||
const label = field?.fieldName || 'Availability';
|
||||
|
||||
if (!availabilityValues || availabilityValues.length === 0) {
|
||||
return {
|
||||
type: '',
|
||||
schedule: [],
|
||||
};
|
||||
const rawValues = (field?.value as string[] | undefined) || [];
|
||||
const labelValues = (field?.valueLabel as string[] | undefined) || [];
|
||||
|
||||
if (rawValues.length === 0) {
|
||||
return { type: '', schedule: [], label };
|
||||
}
|
||||
|
||||
// Map values to human-readable labels
|
||||
const schedule = availabilityValues.map(val =>
|
||||
availabilityLabels[val] || val.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase())
|
||||
);
|
||||
// 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 val.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
|
||||
});
|
||||
|
||||
// Determine type based on values
|
||||
// Deduplicate by normalized comparison (case/whitespace insensitive)
|
||||
const seen = new Set<string>();
|
||||
const schedule: string[] = [];
|
||||
for (const item of resolvedLabels) {
|
||||
const key = item.toLowerCase().replace(/[\s,.-]+/g, '');
|
||||
if (!seen.has(key)) {
|
||||
seen.add(key);
|
||||
schedule.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine availability type based on values OR resolved labels
|
||||
const allValues = [...rawValues.map(v => String(v)), ...resolvedLabels];
|
||||
let type = 'Available';
|
||||
if (availabilityValues.includes('full_time') || availabilityValues.includes('mf_9_5') || availabilityValues.includes('mf_8_6')) {
|
||||
if (allValues.some(v => matchesKeyword(v, fullTimeKeywords))) {
|
||||
type = 'Full-time';
|
||||
} else if (availabilityValues.includes('part_time')) {
|
||||
} else if (allValues.some(v => matchesKeyword(v, partTimeKeywords))) {
|
||||
type = 'Part-time';
|
||||
} else if (availabilityValues.includes('flexible')) {
|
||||
} else if (allValues.some(v => matchesKeyword(v, flexibleKeywords))) {
|
||||
type = 'Flexible';
|
||||
}
|
||||
|
||||
return {
|
||||
type,
|
||||
schedule,
|
||||
};
|
||||
return { type, schedule, label };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user