feat: implement radio field value expansion for ordinal filter matching in agent search

This commit is contained in:
pradeepkumar
2026-04-16 07:29:36 +05:30
parent 623fb9283f
commit 9245ab91ef

View File

@@ -457,6 +457,43 @@ export class AgentsService {
where.agentTypeId = agentTypeId;
}
// Pre-compute RADIO option expansion map for filter matching.
// For ordinal RADIO fields (e.g. years_in_business), selecting "2+" should
// also match "5+" and "10+" — all options at or above the selected index.
let radioExpansionMap: Map<string, string[]> | null = null;
if (filters) {
try {
const pf: Record<string, string[]> = JSON.parse(filters);
const slugs = Object.keys(pf).filter(k => pf[k]?.length > 0);
if (slugs.length > 0) {
const radioFields = await this.prisma.profileField.findMany({
where: { slug: { in: slugs }, fieldType: 'RADIO' },
select: { slug: true, options: true },
});
radioExpansionMap = new Map();
for (const rf of radioFields) {
if (!Array.isArray(rf.options)) continue;
const optValues = (rf.options as Array<{ value: string }>).map(o => String(o.value));
radioExpansionMap.set(rf.slug, optValues);
}
}
} catch { /* invalid JSON — ignore */ }
}
const expandRadioValuesFromMap = (slug: string, selected: string[]): string[] => {
if (!radioExpansionMap) return selected;
const optValues = radioExpansionMap.get(slug);
if (!optValues) return selected;
const expanded = new Set(selected);
for (const sv of selected) {
const idx = optValues.indexOf(sv);
if (idx >= 0) {
for (let i = idx; i < optValues.length; i++) expanded.add(optValues[i]);
}
}
return [...expanded];
};
// Process dynamic profile field filters
if (filters) {
try {
@@ -464,12 +501,14 @@ export class AgentsService {
const filterSlugs = Object.keys(parsedFilters);
if (filterSlugs.length > 0) {
// Get field IDs for the filter slugs
// Get field IDs + type + options for the filter slugs
const fields = await this.prisma.profileField.findMany({
where: { slug: { in: filterSlugs } },
select: {
id: true,
slug: true,
fieldType: true,
options: true,
},
});
@@ -485,9 +524,10 @@ export class AgentsService {
// Use AND logic between different filter slugs, OR logic within same slug
const filterConditions: string[][] = [];
for (const [slug, selectedValues] of Object.entries(parsedFilters)) {
for (const [slug, rawSelectedValues] of Object.entries(parsedFilters)) {
const slugFields = slugToFields.get(slug);
if (!slugFields || slugFields.length === 0 || !selectedValues || selectedValues.length === 0) continue;
if (!slugFields || slugFields.length === 0 || !rawSelectedValues || rawSelectedValues.length === 0) continue;
const selectedValues = expandRadioValuesFromMap(slug, rawSelectedValues);
// Search across ALL fields with this slug (e.g. loan_type in both Professional and Lender sections)
const allMatchingAgentIds: string[] = [];
@@ -673,7 +713,9 @@ export class AgentsService {
if (filterKeys.length > 0) {
let matchedFilters = 0;
for (const filterSlug of filterKeys) {
const selectedValues = parsedFilters[filterSlug];
// Expand RADIO filters so "2+" also matches "5+", "10+", etc.
const rawSelected = parsedFilters[filterSlug];
const selectedValues = expandRadioValuesFromMap(filterSlug, rawSelected);
const agentFieldValues = (agent.fieldValues || []) as any[];
const fieldMatch = agentFieldValues.some((fv: any) => {
if (fv.field?.slug !== filterSlug) return false;