Skip to content

Commit

Permalink
display airports matched by airportcode first
Browse files Browse the repository at this point in the history
  • Loading branch information
its-felix committed Aug 26, 2024
1 parent f3f3de5 commit 8593b42
Showing 1 changed file with 56 additions and 3 deletions.
59 changes: 56 additions & 3 deletions ui/src/components/select/airport-multiselect.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Airports } from '../../lib/api/api.model';
import React, { useMemo } from 'react';
import React, { useMemo, useState } from 'react';
import { Multiselect, MultiselectProps } from '@cloudscape-design/components';

export interface AirportMultiselectProps {
Expand All @@ -11,6 +11,7 @@ export interface AirportMultiselectProps {
}

export function AirportMultiselect({ airports, selectedAirportCodes, loading, disabled, onChange }: AirportMultiselectProps) {
const [filterText, setFilterText] = useState('');
const [options, optionByAirportCode] = useMemo(() => {
const options: Array<MultiselectProps.Option | MultiselectProps.OptionGroup> = [];
const optionByAirportCode: Record<string, MultiselectProps.Option> = {};
Expand Down Expand Up @@ -50,6 +51,15 @@ export function AirportMultiselect({ airports, selectedAirportCodes, loading, di
return [options, optionByAirportCode];
}, [airports]);

const displayOptions = useMemo(() => {
const filter = filterText.trim();
if (filter === '') {
return options;
}

return filterOptions(filter.toUpperCase(), options)[0];
}, [filterText, options]);

const selectedOptions = useMemo(() => {
const result: Array<MultiselectProps.Option> = [];
for (const airportCode of selectedAirportCodes) {
Expand All @@ -64,15 +74,58 @@ export function AirportMultiselect({ airports, selectedAirportCodes, loading, di

return (
<Multiselect
options={options}
options={displayOptions}
selectedOptions={selectedOptions}
onChange={(e) => onChange(e.detail.selectedOptions.flatMap((v) => v.value ? [v.value] : []))}
keepOpen={true}
virtualScroll={true}
filteringType={'auto'}
tokenLimit={2}
disabled={disabled}
statusType={loading ? 'loading' : 'finished'}
filteringType={'manual'}
onLoadItems={(e) => setFilterText(e.detail.filteringText)}
/>
);
}

function filterOptions(filter: string, options: ReadonlyArray<MultiselectProps.Option | MultiselectProps.OptionGroup>): [ReadonlyArray<MultiselectProps.Option | MultiselectProps.OptionGroup>, boolean] {
const matchByLabel: Array<MultiselectProps.Option | MultiselectProps.OptionGroup> = [];
const matchByDescription: Array<MultiselectProps.Option | MultiselectProps.OptionGroup> = [];

for (const option of options) {
const label = option.label?.toUpperCase();
const description = option.description?.toUpperCase();
let matched = false;

if (label?.includes(filter)) {
matchByLabel.push(option);
matched = true;
} else if (isOptionGroup(option)) {
const [filtered, anyMatchedByLabel] = filterOptions(filter, option.options);
if (filtered.length > 0) {
const filteredOption = {
...option,
options: filtered,
} satisfies MultiselectProps.OptionGroup;

if (anyMatchedByLabel) {
matchByLabel.push(filteredOption);
} else {
matchByDescription.push(filteredOption);
}

matched = true;
}
}

if (!matched && description?.includes(filter)) {
matchByDescription.push(option);
}
}

return [[...matchByLabel, ...matchByDescription], matchByLabel.length > 0];
}

function isOptionGroup(option: MultiselectProps.Option | MultiselectProps.OptionGroup): option is MultiselectProps.OptionGroup {
return !!(option as MultiselectProps.OptionGroup).options;
}

0 comments on commit 8593b42

Please sign in to comment.