import * as React from 'react'; import * as classNames from 'classnames'; import {Component, HTMLProps, SFC, ReactElement, ReactNode, Ref} from 'react'; import {DatagridCards} from './DatagridCards'; import {DatagridFilters} from './DatagridFilters'; import {DatagridHeader} from './DatagridHeader'; import {DatagridPagination} from './DatagridPagination'; import {DatagridTable, TableProps} from './DatagridTable'; import {ColumnHeaderProperty, Query, SelectOption, ViewMode} from './models'; import {Scrollbars} from './../'; export interface DatagridProps { defaultFilterDisabled?: boolean; filtersActive?: boolean; progress?: number; loading?: boolean; limitOptions?: number[]; mainButton?: HTMLProps; noDefaultFilter?: boolean; noFilters?: boolean; noFiltersHeader?: boolean; noHeader?: boolean; noPagination?: boolean; noSearchBarCollapse?: boolean; noSearchBy?: boolean; noTotalInHeader?: boolean; noViewModeButton?: boolean; properties?: ColumnHeaderProperty[]; query?: Query; searchInputPlaceholder?: string; searchPropertyOptions?: SelectOption[]; searchPropertyValue?: string; searchTerm?: string; total?: number; tableMinWidth?: number; viewMode?: ViewMode; viewModeButtons?: ViewMode[]; viewModeCustomElement?: ReactNode; onChangeQuery?: (updatedQuery: Query) => void; onChangeSearchProperty?: (searchProperty: string) => void; onChangeViewMode?: (viewMode: ViewMode) => void; onResetAllFilters?: () => void; onSearchTerm?: (term: string) => void; onToggleFilters?: (active: boolean) => void; } export interface DatagridState { filtersActive: boolean; viewMode: ViewMode; } const style = { progress: (progress: number) => ({width: `${progress}%` }), }; export class Datagrid extends Component { static propTypes: any = { children: (props, propName, componentName) => { const children: any[] = props[propName] && (Array.isArray(props[propName]) ? props[propName] : [props[propName]]); if (!children) { return; } const childrenHasNotAllowedElements = children .some(c => typeof c.type === 'string' || (c.type.displayName !== 'DatagridTableView' && c.type.displayName !== 'DatagridCardsView' && c.type.displayName !== 'DatagridMapView' && c.type.displayName !== 'DatagridFiltersSlot')); if (childrenHasNotAllowedElements) { console.warn('Prop `' + propName + '` supplied to `' + componentName + '` has invalid elements.' + ' `' + componentName + '` only accepts children of type `DatagridTableView`, `DatagridCardsView`, `DatagridMapView` and `DatagridFiltersSlot`.' + ' Others components will be ignored.'); return; } }, }; static defaultProps: Partial = { defaultFilterDisabled: false, filtersActive: true, loading: false, progress: 100, limitOptions: [50, 100, 200], mainButton: undefined, noDefaultFilter: false, noFilters: false, noFiltersHeader: false, noHeader: false, noPagination: false, noSearchBarCollapse: false, noSearchBy: false, noTotalInHeader: false, noViewModeButton: false, properties: [], query: { sort: '', limit: 50, skip: 0, }, searchInputPlaceholder: 'Search', searchPropertyOptions: [], searchPropertyValue: '', searchTerm: '', tableMinWidth: 1000, total: 0, viewMode: ViewMode.Table, viewModeButtons: [ ViewMode.Table, ViewMode.Cards, ViewMode.Map, ], viewModeCustomElement: null, onChangeQuery: () => { return; }, onChangeSearchProperty: () => { return; }, onChangeViewMode: () => { return; }, onResetAllFilters: () => { return; }, onSearchTerm: () => { return; }, onToggleFilters: () => { return; }, }; constructor(props: DatagridProps) { super(props); this.state = { filtersActive: props.filtersActive, viewMode: props.viewMode, }; } componentWillReceiveProps(nextProps: DatagridProps) { if (this.props.viewMode !== nextProps.viewMode) { this.setState({viewMode: nextProps.viewMode}); } if (this.props.filtersActive !== nextProps.filtersActive) { this.setState({filtersActive: nextProps.filtersActive}); } } render() { const { loading, progress, defaultFilterDisabled, noDefaultFilter, noFilters, noFiltersHeader, noHeader, noPagination, noSearchBarCollapse, noSearchBy, noTotalInHeader, noViewModeButton, limitOptions, mainButton, properties, query, searchInputPlaceholder, searchPropertyOptions, searchPropertyValue, searchTerm, tableMinWidth, total, viewModeButtons, viewModeCustomElement, onChangeSearchProperty, onResetAllFilters, onSearchTerm} = this.props; const {filtersActive, viewMode} = this.state; if (!this.props.children) { return null; } const children = this.getChildrenAsArray(); const filters = children.filter(node => (node.type as SFC).displayName === 'DatagridFiltersSlot'); return (
{!noHeader && ( onChangeSearchProperty(e.target.value)} onChangeViewMode={this.handleChangeViewMode} onClickToggleFiltersButton={this.handleToggleFilters} /> )}
{this.renderTableView(children)} {this.renderCardsView(children)} {this.renderMapView(children)} {!noPagination && ( )}
{!noFilters && (
{filters}
)}
); } renderTableView = (children: ReactElement[]) => { const {properties, query, tableMinWidth} = this.props; const {viewMode} = this.state; const tableView = children.filter(node => (node.type as SFC).displayName === 'DatagridTableView'); const visible = viewMode === ViewMode.Table && tableView && tableView.length > 0; return visible && ( {tableView} ); } renderCardsView = (children: ReactElement[]) => { const {viewMode} = this.state; const cardsView = children.filter(node => (node.type as SFC).displayName === 'DatagridCardsView'); const visible = viewMode === ViewMode.Cards && cardsView && cardsView.length > 0; return visible && ( {cardsView} ); } renderMapView(children: ReactElement[]) { const {viewMode} = this.state; const mapView = children.find(node => (node.type as SFC).displayName === 'DatagridMapView'); const visible = viewMode === ViewMode.Map && mapView; const mapViewClone = React.cloneElement(mapView, { ...mapView.props, visible, }); return mapViewClone; } handleToggleFilters = () => { this.setState({filtersActive: !this.state.filtersActive}, () => { this.props.onToggleFilters(this.state.filtersActive); }); } handleChangeViewMode = (viewMode: ViewMode) => { this.setState({viewMode}); this.props.onChangeViewMode(viewMode); } handleQueryChange = (queryProp: string) => (value: any) => { const {query, onChangeQuery} = this.props; const updatedQuery = {...query, [queryProp]: value}; this.props.onChangeQuery(updatedQuery); } getChildrenAsArray() { return React.Children.toArray(this.props.children) as ReactElement[]; } }