import type { IModelFilter, IModelFilterOptions, IWebcamFacet } from '../../types'; import { WEBCAM_EXCLUDED_FACETS, WEBCAM_FACET_PREFIX, WEBCAM_FILTER_ANY, WEBCAM_FILTER_GROUPS, WEBCAM_QUICK_FACETS, } from './facets'; /** * Приводит фасеты провайдера к фильтрам слоя. * * Правила скрытия и исключений взяты с боевого движка: технические фасеты не * рисуются, вырожденные контролы (один вариант, слипшийся диапазон) — тоже. * * Селектам добавляем вариант «любой» первым: в разметке слоя первая опция — это * значение «фильтр не выбран», без неё нельзя выбрать то, что стоит первым в * списке. Диапазонам такой вариант не нужен — у них границы. * * @param facets - фасеты из ответа провайдера * @param total - всего моделей в текущей выдаче (подпись у варианта «любой») */ export function normalizeWebcamFacets(facets: IWebcamFacet[] | null | undefined, total = 0): IModelFilter[] { return (facets || []).reduce((result, facet) => { const name = String(facet.name || '').replace(WEBCAM_FACET_PREFIX, ''); if (!name || WEBCAM_EXCLUDED_FACETS.includes(name)) return result; // пустое значение у провайдера означает «не указано» — как вариант выбора // оно бессмысленно (в старом движке такие опции тоже отбрасывались) const options = (facet.options || []).filter(option => option.name !== ''); const isRange = facet.kind === 'range'; if (isRange && !isRangeUsable(options)) return result; if (!isRange && options.length < 2) return result; const group = WEBCAM_QUICK_FACETS.includes(name) ? WEBCAM_FILTER_GROUPS.quick : WEBCAM_FILTER_GROUPS.more; result.push({ name, title: String(facet.title || name), kind: String(facet.kind || 'select'), options: isRange ? options : [{ name: WEBCAM_FILTER_ANY, title: WEBCAM_FILTER_ANY, quantity: total }, ...options], group: { name: group.name, title: group.name, order: group.order, description: '' }, icon: '', show_on_form: true, }); return result; }, []); } /** Диапазон имеет смысл, только если границы разные. */ function isRangeUsable(options: IModelFilterOptions[]): boolean { const values = options.map(option => Number(option.name)).filter(value => !isNaN(value)); return values.length > 1 && Math.min(...values) !== Math.max(...values); }