76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
import { useCallback, useMemo, useRef } from "react";
|
|
import {
|
|
FormField,
|
|
SearchableSelect,
|
|
type ApiSettings,
|
|
type SearchableSelectOption
|
|
} from "@govoplan/core-webui";
|
|
import {
|
|
listDistributionLists,
|
|
type DistributionList
|
|
} from "../api/distLists";
|
|
import { DIST_LISTS_FIELD_DOCUMENTATION } from "../features/distributionLists/interfacePatterns";
|
|
|
|
export type DistributionListPickerProps = {
|
|
settings: ApiSettings;
|
|
value: string;
|
|
onChange: (listId: string, item: DistributionList | null) => void;
|
|
label?: string;
|
|
placeholder?: string;
|
|
disabled?: boolean;
|
|
required?: boolean;
|
|
selected?: DistributionList | null;
|
|
};
|
|
|
|
export default function DistributionListPicker({
|
|
settings,
|
|
value,
|
|
onChange,
|
|
label = "Distribution list",
|
|
placeholder = "Search distribution lists",
|
|
disabled = false,
|
|
required = false,
|
|
selected = null
|
|
}: DistributionListPickerProps) {
|
|
const cache = useRef(new Map<string, DistributionList>());
|
|
if (selected) cache.current.set(selected.id, selected);
|
|
|
|
const selectedOption = useMemo<SearchableSelectOption | null>(() => {
|
|
const item = selected ?? cache.current.get(value);
|
|
if (!item) return value ? { value, label: value } : null;
|
|
return optionFor(item);
|
|
}, [selected, value]);
|
|
|
|
const loadOptions = useCallback(async (query: string) => {
|
|
const items = await listDistributionLists(settings, query);
|
|
for (const item of items) cache.current.set(item.id, item);
|
|
return items.map(optionFor);
|
|
}, [settings]);
|
|
|
|
return (
|
|
<FormField label={label} documentation={DIST_LISTS_FIELD_DOCUMENTATION}>
|
|
<SearchableSelect
|
|
value={value}
|
|
selectedOption={selectedOption}
|
|
loadOptions={loadOptions}
|
|
onChange={(nextValue) =>
|
|
onChange(nextValue, cache.current.get(nextValue) ?? null)}
|
|
placeholder={placeholder}
|
|
searchPlaceholder="Search by list name"
|
|
emptyText="No matching distribution lists."
|
|
disabled={disabled}
|
|
required={required}
|
|
/>
|
|
</FormField>
|
|
);
|
|
}
|
|
|
|
function optionFor(item: DistributionList): SearchableSelectOption {
|
|
return {
|
|
value: item.id,
|
|
label: item.name,
|
|
description: `${item.revision.entries.length} entries · revision ${item.current_revision}`,
|
|
searchText: `${item.description ?? ""} ${item.scope_type}`
|
|
};
|
|
}
|