nope/resources/ui/layout/selection.tsx
Martin Karkowski 39adf1faea Moving Files
2020-09-07 10:27:10 +02:00

199 lines
7.6 KiB
TypeScript

import React from 'react';
import { FormControl, InputGroup, ListGroup } from 'react-bootstrap';
import { deepClone } from '../../../lib/helpers/objectMethods';
export interface SelecitonProps<T> {
selection: Array<{
groupName: string,
items: SelectionItem<T>[]
} | SelectionItem<T>>,
onItemSelected?: (item: T) => void;
allowUserSelect?: boolean;
}
export interface SelectionItem<T> {
label: string,
keywords: string,
item: T,
id: string | number,
color?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'light'
}
export interface LayoutState<T> {
selected: string | number;
search: string;
}
class Selection<T> extends React.Component<SelecitonProps<T>, LayoutState<T>> {
constructor(props) {
super(props);
this.state = {
search: '',
selected: null
}
}
/**
* Function to Filter the Selection.
* @param search The Search Term.
*/
protected _filter(search: string) {
this.setState({
search: search.toLocaleLowerCase(),
selected: this.state.selected
});
}
/**
* Function used to Select an item
* @param item which will be selected
*/
protected _select(item: SelectionItem<T>) {
this.setState({
search: this.state.search,
selected: this.props.allowUserSelect ? item.id : -1
});
if (this.props.allowUserSelect && typeof this.props.onItemSelected === "function") {
this.props.onItemSelected(item.item);
}
}
public render() {
const _this = this;
// Filter only Valid items.
// Therefore iterate over the Groups and
// Filter the Items with the Search String
// and there Labels / Keywords.
// Afterwards filter the groups and remove
// Empty Groups
const items = deepClone(this.props).selection.map(item => {
if ((item as {
groupName: string,
items: SelectionItem<T>[]
}).items !== undefined) {
// Filter the Items, that match the Selection
(item as {
groupName: string,
items: SelectionItem<T>[]
}).items = (item as {
groupName: string,
items: SelectionItem<T>[]
}).items.filter(value =>
// Filter the Keywords
value.keywords.toLowerCase().includes(_this.state.search) ||
// Filter the Lable.
value.label.toLowerCase().includes(_this.state.search)
);
}
// Return the Item
return item;
}).filter(
item => {
// Filter the Element by the lenght of the contained elements.
if ((item as {
groupName: string,
items: SelectionItem<T>[]
}).items !== undefined) {
// Filter the Keywords
return (item as {
groupName: string,
items: SelectionItem<T>[]
}).items.length > 0;
} else {
// Filter the Keywords
return (item as SelectionItem<T>).keywords.toLowerCase().includes(_this.state.search) ||
// Filter the Lable.
(item as SelectionItem<T>).label.toLowerCase().includes(_this.state.search)
}
}
);
let idx = 0;
return (<>
{/* A Search Field. */}
{this.props.allowUserSelect ?
<InputGroup size="sm" className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="inputGroup-sizing-sm" >Search</InputGroup.Text>
</InputGroup.Prepend>
<FormControl aria-label="Small" aria-describedby="inputGroup-sizing-sm" onChange={(event) => {
_this._filter(event.currentTarget.value);
}} />
</InputGroup> : ''
}
{
items.length > 0 ?
items.map(item => {
idx++;
if ((item as {
groupName: string,
items: SelectionItem<T>[]
}).items !== undefined) {
return (
<div key={idx}>
<hr />
<h4>{(item as {
groupName: string,
items: SelectionItem<T>[]
}).groupName}</h4>
<hr />
<ListGroup>
{(item as {
groupName: string,
items: SelectionItem<T>[]
}).items.map(template => {
// Raise the ID
idx++;
// Store the Item Index
const idxOfItem = idx;
// Based on the selected Item assign the Color
// dark = selected
// light = unselected
const variant = _this.props.allowUserSelect ?
(template.id === _this.state.selected ? "dark" : "light") :
template.color || 'light';
// Return the Template variant={variant}
return (
<ListGroup.Item key={idxOfItem} action variant={variant} onClick={e => {
_this._select(template)
}}>{template.label}</ListGroup.Item>
);
})}
</ListGroup>
</div>
);
} else {
// Store the Item Index
const idxOfItem = idx;
// Based on the selected Item assign the Color
// dark = selected
// light = unselected
const variant = _this.props.allowUserSelect ?
((item as SelectionItem<T>).id === _this.state.selected ? "dark" : "light") :
(item as SelectionItem<T>).color || 'light';
// Return the Template variant={variant}
return (
<ListGroup.Item key={idxOfItem} action variant={variant} onClick={e => {
_this._select(item as SelectionItem<T>)
}}>{(item as SelectionItem<T>).label}</ListGroup.Item>
)
}
}) :
<code>Nothing Found</code>
}
</>);
}
}
export default Selection;