feat: implement radio field value expansion for ordinal filter matching in agent search
This commit is contained in:
@@ -457,6 +457,43 @@ export class AgentsService {
|
|||||||
where.agentTypeId = agentTypeId;
|
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
|
// Process dynamic profile field filters
|
||||||
if (filters) {
|
if (filters) {
|
||||||
try {
|
try {
|
||||||
@@ -464,12 +501,14 @@ export class AgentsService {
|
|||||||
const filterSlugs = Object.keys(parsedFilters);
|
const filterSlugs = Object.keys(parsedFilters);
|
||||||
|
|
||||||
if (filterSlugs.length > 0) {
|
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({
|
const fields = await this.prisma.profileField.findMany({
|
||||||
where: { slug: { in: filterSlugs } },
|
where: { slug: { in: filterSlugs } },
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
slug: 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
|
// Use AND logic between different filter slugs, OR logic within same slug
|
||||||
const filterConditions: string[][] = [];
|
const filterConditions: string[][] = [];
|
||||||
|
|
||||||
for (const [slug, selectedValues] of Object.entries(parsedFilters)) {
|
for (const [slug, rawSelectedValues] of Object.entries(parsedFilters)) {
|
||||||
const slugFields = slugToFields.get(slug);
|
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)
|
// Search across ALL fields with this slug (e.g. loan_type in both Professional and Lender sections)
|
||||||
const allMatchingAgentIds: string[] = [];
|
const allMatchingAgentIds: string[] = [];
|
||||||
@@ -673,7 +713,9 @@ export class AgentsService {
|
|||||||
if (filterKeys.length > 0) {
|
if (filterKeys.length > 0) {
|
||||||
let matchedFilters = 0;
|
let matchedFilters = 0;
|
||||||
for (const filterSlug of filterKeys) {
|
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 agentFieldValues = (agent.fieldValues || []) as any[];
|
||||||
const fieldMatch = agentFieldValues.some((fv: any) => {
|
const fieldMatch = agentFieldValues.some((fv: any) => {
|
||||||
if (fv.field?.slug !== filterSlug) return false;
|
if (fv.field?.slug !== filterSlug) return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user