import {
|
|
ChangeEvent,
|
|
FC,
|
|
ReactElement,
|
|
ReactEventHandler,
|
|
useState,
|
|
} from "react";
|
|
|
|
interface ItemProps<Item> {
|
|
name: string;
|
|
data: Item;
|
|
}
|
|
|
|
interface ListProps<Item> {
|
|
title: string;
|
|
onRefresh: ReactEventHandler;
|
|
component: FC<ItemProps<Item>>;
|
|
map: { [key: string]: Item };
|
|
}
|
|
|
|
function SearchableList<Item>({
|
|
title,
|
|
onRefresh,
|
|
component,
|
|
map,
|
|
}: ListProps<Item>): ReactElement {
|
|
const [filter, setFilter] = useState<string>("");
|
|
|
|
const onChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
setFilter(event.target.value);
|
|
};
|
|
|
|
const children = [];
|
|
for (const name in map) {
|
|
if (name.includes(filter)) {
|
|
children.push(<li key={name}>{component({ name, data: map[name] })}</li>);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="flex flex-col px-3 h-full">
|
|
<div className="flex justify-between p-3">
|
|
<h1 className="pl-3 text-2xl font-bold text-yellow-800 text-center">
|
|
{title}
|
|
</h1>
|
|
<button onClick={onRefresh} className="button">
|
|
Refresh
|
|
</button>
|
|
</div>
|
|
<form className="flex gap-3 p-3">
|
|
<label htmlFor="filter" className="self-center">
|
|
Filter:
|
|
</label>
|
|
<input
|
|
name="filter"
|
|
type="text"
|
|
className="text-input flex-grow"
|
|
value={filter}
|
|
onChange={onChange}
|
|
/>
|
|
</form>
|
|
<ul className="flex-1 flex flex-col min-h-0 overflow-auto">{children}</ul>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default SearchableList;
|