components.widgets.StandardWidget.tsx Maven / Gradle / Ivy
import React, { Children, useCallback, useMemo, ReactNode, CSSProperties, memo } from 'react'
import classNames from 'classnames'
import { connect } from 'react-redux'
import { createStructuredSelector } from 'reselect'
import { isEmpty } from 'lodash'
import { SpinnerType } from '@i-novus/n2o-components/lib/layouts/Spinner/Spinner'
import Toolbar, { ToolbarProps } from '../buttons/Toolbar'
import { Spinner } from '../snippets/Spinner/Spinner'
import { dataSourceError } from '../../ducks/datasource/selectors'
import { ErrorContainer } from '../../core/error/Container'
import { State } from '../../ducks/State'
import { type ErrorContainerProps } from '../../core/error/types'
import { Model } from '../../ducks/models/selectors'
import { WidgetFilters, type Props as WidgetFiltersProps } from './WidgetFilters'
export enum PLACES {
top = 'top',
left = 'left',
right = 'right',
center = 'center',
topLeft = 'topLeft',
topRight = 'topRight',
topCenter = 'topCenter',
bottomLeft = 'bottomLeft',
bottomRight = 'bottomRight',
bottomCenter = 'bottomCenter',
}
export interface Props {
widgetId: string
toolbar: Record
filter?: { filterPlace: PLACES, filterFieldsets: WidgetFiltersProps['fieldsets'] }
fetchData?: WidgetFiltersProps['fetchData']
datasource: string
pagination?: Record
disabled?: boolean
className?: string
style?: CSSProperties
children: ReactNode
loading: boolean
error: ErrorContainerProps['error']
activeModel?: Model | Model[]
}
/**
* Виджет таблица
* @reactProps {string} widgetId - id виджета
* @reactProps {Object} toolbar
* @reactProps {Object} filter
* @reactProps {boolean} disabled - флаг активности
* @reactProps {node} children - элемент потомок компонента StandardWidget
*/
const StandardWidget = memo(({
widgetId,
fetchData,
datasource,
disabled,
className,
style,
children,
loading,
error,
filter = {} as never,
toolbar = {},
pagination = {},
}: Props) => {
const renderToolbar = useCallback((place) => {
const paginationComponent = pagination[place]
const currentToolbar = toolbar[place]
const toolbarClassNames = classNames(
'd-flex',
'flex-column',
'n2o-standard-widget-layout-toolbar-wrapper',
`n2o-standard-widget-layout-toolbar--${place.toLowerCase().replace(/(bottom)|(top)/, '')}`,
{
'flex-column-reverse': place.includes(PLACES.top),
},
)
return (
currentToolbar || paginationComponent ? (
{paginationComponent}
{currentToolbar ? : null}
) : null
)
}, [pagination, toolbar, widgetId])
const filterComponent = (
)
const { topToolbars, bottomToolbars } = useMemo(() => ({
topToolbars: [
renderToolbar(PLACES.topLeft),
renderToolbar(PLACES.topCenter),
renderToolbar(PLACES.topRight),
].filter(Boolean),
bottomToolbars: [
renderToolbar(PLACES.bottomLeft),
renderToolbar(PLACES.bottomCenter),
renderToolbar(PLACES.bottomRight),
].filter(Boolean),
}), [renderToolbar])
const classes = classNames([
className,
'n2o-standard-widget-layout',
{ 'n2o-disabled': disabled },
])
const errorComponent = isEmpty(error) ? null :
const childrenWithError = Children.map(children, (child) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { errorComponent } as never)
}
return child
})
return (
{filter.filterPlace === PLACES.left ? (
{filterComponent}
) : null}
{filter.filterPlace === PLACES.top ? (
{filterComponent}
) : null}
{topToolbars.length ? (
{topToolbars}
) : null}
{childrenWithError}
{bottomToolbars.length ? (
{bottomToolbars}
) : null}
{filter.filterPlace === PLACES.right ? (
{filterComponent}
) : null}
)
})
const mapStateToProps = createStructuredSelector({
// @ts-ignore TODO объеденить типы ErrorContainerProps['error'] и dataSourceError, убрать as never
error: (state: State, { datasource }: Props) => {
if (state.datasource[datasource]) {
return dataSourceError(datasource)(state)
}
return null
},
})
// @ts-ignore TODO объеденить типы ErrorContainerProps['error'] и dataSourceError, убрать as never
export default connect(mapStateToProps)(StandardWidget)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy