@@ -8,62 +8,155 @@ import { capitalize, has, isPlainObject } from 'lodash';
88import SCHEMA_DEFINITIONS from 'configs/schema-definitions.json' ;
99import { SchemaDefinitions } from 'scripts/generate-schema-definitions/types' ;
1010
11- /**
12- * Controls how a selected filter is displayed in the tag.
13- */
11+ // Constants
12+ const DISPLAY_NAME_SEPARATOR = ' | ' ;
13+ const DATE_FILTER_KEY = 'date' ;
14+ const EXISTS_PREFIX = '_exists_' ;
15+ const NOT_EXISTS_PREFIX = '-_exists_' ;
16+
17+ const schema = SCHEMA_DEFINITIONS as SchemaDefinitions ;
18+
19+ // Type guards
20+ const isStringValue = ( value : unknown ) : value is string =>
21+ typeof value === 'string' ;
22+
23+ const isObjectValue = ( value : unknown ) : value is Record < string , unknown > =>
24+ isPlainObject ( value ) ;
25+
26+ const isDateRangeValues = (
27+ values : ( string | SelectedFilterTypeValue ) [ ] ,
28+ ) : values is [ string , string ] =>
29+ values . length === 2 && isStringValue ( values [ 0 ] ) && isStringValue ( values [ 1 ] ) ;
30+
31+ // Helper Functions
32+
33+ // Formats a display name with common and scientific names
34+ const formatDisplayName = ( value : string ) : string => {
35+ if ( ! value . includes ( DISPLAY_NAME_SEPARATOR ) ) {
36+ return value ;
37+ }
38+
39+ const [ commonName , scientificName ] = value . split ( DISPLAY_NAME_SEPARATOR ) ;
40+ return `${ capitalize ( scientificName ) } (${ capitalize ( commonName ) } )` ;
41+ } ;
42+
43+ // Formats a date range for display
44+ const formatDateRange = ( startDate : string , endDate : string ) : string =>
45+ `From ${ startDate } to ${ endDate } ` ;
46+
47+ // Applies custom label transformation from filter config
48+ const applyConfigTransform = ( value : string , config ?: FilterConfig ) : string => {
49+ if ( ! config ?. transformData ) {
50+ return value ;
51+ }
52+
53+ return config . transformData ( { term : value , count : 0 } ) ?. label || value ;
54+ } ;
55+
56+ // Controls how a selected filter is displayed in the tag
1457const getDisplayValue = (
1558 key : string ,
1659 value : string | SelectedFilterTypeValue ,
1760 values : ( string | SelectedFilterTypeValue ) [ ] ,
1861 index : number ,
1962 config ?: FilterConfig ,
2063) : string => {
21- if ( isPlainObject ( value ) ) {
64+ // Handle object values (exists/not exists queries)
65+ if ( isObjectValue ( value ) ) {
2266 const objectKey = Object . keys ( value ) [ 0 ] ;
23- return objectKey . startsWith ( '-_exists_' ) ? 'None' : 'Any' ;
67+ return objectKey ? .startsWith ( NOT_EXISTS_PREFIX ) ? 'None' : 'Any' ;
2468 }
2569
26- // Format date ranges
27- if (
28- key === 'date' &&
29- values . length === 2 &&
30- typeof values [ 0 ] === 'string' &&
31- typeof values [ 1 ] === 'string'
32- ) {
33- if ( index > 0 ) return '' ;
34- return `From ${ values [ 0 ] } to ${ values [ 1 ] } ` ;
70+ // Handle date ranges (skip subsequent values in range)
71+ if ( key === DATE_FILTER_KEY && isDateRangeValues ( values ) ) {
72+ return index === 0 ? formatDateRange ( values [ 0 ] , values [ 1 ] ) : '' ;
3573 }
3674
37- // Display names that have it, with both common and scientific forms
38- if ( typeof value === 'string' ) {
39- if ( key . includes ( 'displayName' ) && value . includes ( ' | ' ) ) {
40- const [ commonName , scientificName ] = value . split ( ' | ' ) ;
41- return ` ${ capitalize ( scientificName ) } ( ${ capitalize ( commonName ) } )` ;
75+ // Handle string values
76+ if ( isStringValue ( value ) ) {
77+ // Format display names
78+ if ( key . includes ( 'displayName' ) ) {
79+ return formatDisplayName ( value ) ;
4280 }
4381
44- // Apply any custom label transformation from config
45- if (
46- ( key === '@type' || key === 'conditionsOfAccess' ) &&
47- config ?. transformData
48- ) {
49- return config . transformData ( { term : value , count : 0 } ) ?. label || '' ;
82+ // Apply config transformations for specific keys
83+ if ( key === '@type' || key === 'conditionsOfAccess' ) {
84+ return applyConfigTransform ( value , config ) ;
5085 }
5186 }
5287
5388 return String ( value ) ;
5489} ;
5590
56- /**
57- * Generates a flat list of tag metadata objects from selected filters.
58- */
59- const schema = SCHEMA_DEFINITIONS as SchemaDefinitions ;
60- export const generateTagName = ( key : string , config ?: FilterConfig ) : string => {
61- if ( config ?. name ) return config . name ;
62- if ( schema ?. [ key ] ?. name ) return schema [ key ] . name ;
91+ // Checks if a filter represents a date exists/not exists query
92+ const isDateExistsQuery = (
93+ key : string ,
94+ values : ( string | SelectedFilterTypeValue ) [ ] ,
95+ ) : boolean => {
96+ if ( key !== DATE_FILTER_KEY || values . length !== 1 ) {
97+ return false ;
98+ }
6399
64- return key ;
100+ const value = values [ 0 ] ;
101+ return (
102+ isObjectValue ( value ) &&
103+ ( has ( value , EXISTS_PREFIX ) || has ( value , NOT_EXISTS_PREFIX ) )
104+ ) ;
65105} ;
66106
107+ // Creates a tag info object for a date range
108+ const createDateRangeTag = (
109+ key : string ,
110+ name : string ,
111+ values : [ string , string ] ,
112+ ) : TagInfo => ( {
113+ key : `${ key } -range` ,
114+ filterKey : key ,
115+ name,
116+ value : values ,
117+ displayValue : formatDateRange ( values [ 0 ] , values [ 1 ] ) ,
118+ } ) ;
119+
120+ // Creates tag info objects for individual filter values
121+ const createValueTags = (
122+ key : string ,
123+ name : string ,
124+ values : ( string | SelectedFilterTypeValue ) [ ] ,
125+ config ?: FilterConfig ,
126+ ) : TagInfo [ ] => {
127+ return values
128+ . map ( ( rawValue , index ) : TagInfo | null => {
129+ const displayValue = getDisplayValue (
130+ key ,
131+ rawValue ,
132+ values ,
133+ index ,
134+ config ,
135+ ) ;
136+
137+ if ( ! displayValue ) {
138+ return null ;
139+ }
140+
141+ return {
142+ key : `${ key } -${ index } ` ,
143+ filterKey : key ,
144+ name,
145+ value : rawValue ,
146+ displayValue,
147+ } ;
148+ } )
149+ . filter ( ( tag ) : tag is TagInfo => tag !== null ) ;
150+ } ;
151+
152+ // Exported functions
153+
154+ // Generates a human-readable name for a filter key
155+ export const generateTagName = ( key : string , config ?: FilterConfig ) : string => {
156+ return config ?. name ?? schema ?. [ key ] ?. name ?? key ;
157+ } ;
158+
159+ // Generates a flat list of tag metadata objects from selected filters
67160export const generateTags = (
68161 selectedFilters : SelectedFilterType ,
69162 configMap : Record < string , FilterConfig > ,
@@ -72,35 +165,17 @@ export const generateTags = (
72165 const config = configMap [ key ] ;
73166 const name = generateTagName ( key , config ) ;
74167
75- if (
76- key === 'date' &&
77- values . length === 1 &&
78- isPlainObject ( values [ 0 ] ) &&
79- ( has ( values [ 0 ] , '_exists_' ) || has ( values [ 0 ] , '-_exists_' ) )
80- ) {
168+ // Skip date exists/not exists queries (they don't display as tags)
169+ if ( isDateExistsQuery ( key , values ) ) {
81170 return [ ] ;
82171 }
83172
84- // Generate tag info for each value
85- return values
86- . map ( ( rawValue , index ) => {
87- const displayValue = getDisplayValue (
88- key ,
89- rawValue ,
90- values ,
91- index ,
92- config ,
93- ) ;
94- if ( ! displayValue ) return null ;
95-
96- return {
97- key : `${ key } -${ index } ` ,
98- filterKey : key ,
99- name,
100- value : rawValue ,
101- displayValue,
102- } ;
103- } )
104- . filter ( Boolean ) as TagInfo [ ] ;
173+ // Handle date ranges as a single tag
174+ if ( key === DATE_FILTER_KEY && isDateRangeValues ( values ) ) {
175+ return [ createDateRangeTag ( key , name , values ) ] ;
176+ }
177+
178+ // Handle all other filters
179+ return createValueTags ( key , name , values , config ) ;
105180 } ) ;
106181} ;
0 commit comments