471 lines
16 KiB
TypeScript
471 lines
16 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||
import Container from '@/components/shared/Container'
|
||
import { DX_CLASSNAMES } from '@/constants/app.constant'
|
||
import { GridDto, ListFormCustomizationTypeEnum } from '@/proxy/form/models'
|
||
import {
|
||
getListFormCustomization,
|
||
postListFormCustomization,
|
||
} from '@/services/list-form-customization.service'
|
||
import { useListFormColumns } from '@/shared/useListFormColumns'
|
||
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
|
||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||
import Chart, { CommonSeriesSettings, Size, Tooltip } from 'devextreme-react/chart'
|
||
import PivotGrid, {
|
||
FieldChooser,
|
||
FieldPanel,
|
||
HeaderFilter,
|
||
IStateStoringProps,
|
||
PivotGridTypes,
|
||
Scrolling,
|
||
Search,
|
||
} from 'devextreme-react/pivot-grid'
|
||
import CustomStore from 'devextreme/data/custom_store'
|
||
import PivotGridDataSource, { Field } from 'devextreme/ui/pivot_grid/data_source'
|
||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||
import { Helmet } from 'react-helmet'
|
||
import { GridColumnData } from './GridColumnData'
|
||
import {
|
||
addCss,
|
||
addJs,
|
||
controlStyleCondition,
|
||
pivotFieldConvertDataType,
|
||
setGridPanelColor,
|
||
} from './Utils'
|
||
import { useFilters } from './useFilters'
|
||
import WidgetGroup from '@/components/common/WidgetGroup'
|
||
import { Button } from '@/components/ui'
|
||
import {
|
||
FaCog,
|
||
FaInfoCircle,
|
||
FaSyncAlt,
|
||
FaTimes,
|
||
FaTrash,
|
||
FaTrashAlt,
|
||
FaUndo,
|
||
} from 'react-icons/fa'
|
||
import { usePermission } from '@/utils/hooks/usePermission'
|
||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||
import { usePWA } from '@/utils/hooks/usePWA'
|
||
|
||
interface PivotProps {
|
||
listFormCode: string
|
||
searchParams?: URLSearchParams
|
||
isSubForm?: boolean
|
||
level?: number
|
||
refreshData?: () => Promise<void>
|
||
gridDto?: GridDto
|
||
refreshGridDto: () => Promise<void>
|
||
}
|
||
|
||
const statedGridPanelColor = 'rgba(50, 200, 200, 0.5)' // kullanici tanimli gridState ile islem gormus gridin paneline ait renk
|
||
|
||
const Pivot = (props: PivotProps) => {
|
||
const { listFormCode, searchParams, isSubForm, level, gridDto } = props
|
||
const { translate } = useLocalization()
|
||
const { checkPermission } = usePermission()
|
||
const isPwaMode = usePWA()
|
||
|
||
const gridRef = useRef<PivotGrid>()
|
||
const chartRef = useRef<Chart>(null)
|
||
const refListFormCode = useRef('')
|
||
|
||
const [gridDataSource, setGridDataSource] = useState<CustomStore<any, any>>()
|
||
const [columnData, setColumnData] = useState<GridColumnData[]>()
|
||
|
||
const { filterToolbarData, ...filterData } = useFilters({
|
||
gridDto,
|
||
gridRef,
|
||
listFormCode,
|
||
})
|
||
|
||
const { createSelectDataSource } = useListFormCustomDataSource({ pivotRef: gridRef })
|
||
const { getBandedColumns } = useListFormColumns({
|
||
gridDto,
|
||
listFormCode,
|
||
isSubForm,
|
||
})
|
||
|
||
function onCellPrepared(e: any) {
|
||
const columnFormats = gridDto?.columnFormats
|
||
if (!columnFormats) {
|
||
return
|
||
}
|
||
|
||
// satir, hucre yada header vb. kisimlara conditional style uygulamak icin
|
||
for (let indxCol = 0; indxCol < columnFormats.length; indxCol++) {
|
||
const colFormat = columnFormats[indxCol]
|
||
for (let indxStyl = 0; indxStyl < colFormat.columnStylingDto.length; indxStyl++) {
|
||
const colStyle = colFormat.columnStylingDto[indxStyl] // uygulanacak style
|
||
if (e.rowType == colStyle.rowType) {
|
||
// header, filter, data, group, summaries ..her birisine style uygulanabilir
|
||
// style bütün satıra uygulansın olarak seçili ise yada sadece ilgili field üzerinde ise
|
||
if (colStyle.useRow || e.column?.dataField == colFormat.fieldName) {
|
||
if (
|
||
!colStyle.conditionValue ||
|
||
controlStyleCondition(e.data, colFormat.fieldName, colStyle)
|
||
) {
|
||
// css sınıf ismi var ise uygula
|
||
if (colStyle.cssClassName) {
|
||
e.cellElement.addClass(colStyle.cssClassName)
|
||
}
|
||
// css inline style var ise uygula
|
||
if (colStyle.cssStyles) {
|
||
e.cellElement.attr('style', e.cellElement.attr('style') + ';' + colStyle.cssStyles)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
const clearPivotFilters = () => {
|
||
const grid = gridRef.current?.instance
|
||
if (!grid) return
|
||
|
||
const ds = grid.getDataSource()
|
||
if (ds) {
|
||
const fields = ds.fields()
|
||
fields.forEach((f: any) => {
|
||
f.filterValues = undefined
|
||
f.filterType = undefined
|
||
})
|
||
ds.reload()
|
||
}
|
||
}
|
||
|
||
const moveAllFieldsToFilterArea = () => {
|
||
const grid = gridRef.current?.instance
|
||
if (!grid) return
|
||
|
||
const ds = grid.getDataSource()
|
||
if (!ds) return
|
||
|
||
const fields = ds.fields()
|
||
|
||
fields.forEach((field) => {
|
||
field.area = 'filter' // tüm alanları filtre alanına taşı
|
||
field.areaIndex = undefined
|
||
})
|
||
|
||
ds.fields(fields)
|
||
ds.reload() // PivotGrid’i yeniden yükle
|
||
grid.repaint() // UI güncelle
|
||
}
|
||
|
||
const resetPivotGridState = async () => {
|
||
const grid = gridRef.current?.instance
|
||
if (grid) {
|
||
// kullaniciya ait kayitli grid state i sil customizationData boşalt silinsin.
|
||
await postListFormCustomization({
|
||
listFormCode: listFormCode,
|
||
customizationType: ListFormCustomizationTypeEnum.GridState,
|
||
filterName: `pivot-${gridRef.current?.instance.option('stateStoring')?.storageKey ?? ''}`,
|
||
customizationData: '',
|
||
})
|
||
|
||
await props.refreshGridDto()
|
||
clearPivotFilters()
|
||
moveAllFieldsToFilterArea()
|
||
}
|
||
}
|
||
|
||
const customSaveState = useCallback(
|
||
(state: any) =>
|
||
postListFormCustomization({
|
||
listFormCode: listFormCode,
|
||
customizationType: ListFormCustomizationTypeEnum.GridState,
|
||
filterName: `pivot-${gridRef.current?.instance.option('stateStoring')?.storageKey ?? ''}`,
|
||
customizationData: JSON.stringify(state),
|
||
}).then(() => {
|
||
setGridPanelColor(statedGridPanelColor)
|
||
}),
|
||
[listFormCode],
|
||
)
|
||
|
||
const customLoadState = useCallback(
|
||
() =>
|
||
getListFormCustomization(
|
||
listFormCode,
|
||
ListFormCustomizationTypeEnum.GridState,
|
||
`pivot-${gridRef.current?.instance.option('stateStoring')?.storageKey ?? ''}`,
|
||
).then((response: any) => {
|
||
setGridPanelColor(statedGridPanelColor)
|
||
if (response.data?.length > 0) {
|
||
return JSON.parse(response.data[0].customizationData)
|
||
}
|
||
}),
|
||
[listFormCode],
|
||
)
|
||
|
||
useEffect(() => {
|
||
if (gridRef?.current) {
|
||
gridRef.current.instance.option('remoteOperations', false)
|
||
gridRef.current.instance.option('dataSource', undefined)
|
||
gridRef.current.instance.option('stateStoring', undefined)
|
||
}
|
||
}, [listFormCode])
|
||
|
||
useEffect(() => {
|
||
if (!gridDto) {
|
||
return
|
||
}
|
||
|
||
// Set js and css
|
||
const grdOpt = gridDto.gridOptions
|
||
if (grdOpt.customJsSources.length) {
|
||
for (const js of grdOpt.customJsSources) {
|
||
addJs(js)
|
||
}
|
||
}
|
||
if (grdOpt.customStyleSources.length) {
|
||
for (const css of grdOpt.customStyleSources) {
|
||
addCss(css)
|
||
}
|
||
}
|
||
}, [gridDto])
|
||
|
||
useEffect(() => {
|
||
if (!gridDto) {
|
||
return
|
||
}
|
||
|
||
// Set columns
|
||
const cols = getBandedColumns()
|
||
setColumnData(cols?.filter((a) => a.colData?.pivotSettingsDto.isPivot))
|
||
|
||
// Set data source
|
||
const dataSource: CustomStore<any, any> = createSelectDataSource(
|
||
gridDto.gridOptions,
|
||
listFormCode,
|
||
searchParams,
|
||
cols,
|
||
)
|
||
|
||
setGridDataSource(dataSource)
|
||
}, [gridDto, searchParams])
|
||
|
||
useEffect(() => {
|
||
refListFormCode.current = listFormCode
|
||
if (!gridRef?.current) {
|
||
return
|
||
}
|
||
|
||
const fields: any = columnData?.map((b) => {
|
||
return {
|
||
dataField: b.dataField,
|
||
caption: b.caption,
|
||
dataType: pivotFieldConvertDataType(b.dataType),
|
||
area: b.colData?.pivotSettingsDto.area,
|
||
format: b.colData?.pivotSettingsDto.format,
|
||
summaryType: b.colData?.pivotSettingsDto.summaryType,
|
||
groupInterval: b.colData?.pivotSettingsDto.groupInterval,
|
||
sortOrder: b.colData?.pivotSettingsDto.sortOrder,
|
||
expanded: b.colData?.pivotSettingsDto.expanded,
|
||
wordWrapEnabled: b.colData?.pivotSettingsDto.wordWrapEnabled,
|
||
visible: true,
|
||
width: b.width,
|
||
} as Field
|
||
})
|
||
|
||
PivotGridDataSource
|
||
const dataSource: PivotGridTypes.Properties['dataSource'] = {
|
||
remoteOperations: true,
|
||
store: gridDataSource,
|
||
fields,
|
||
}
|
||
|
||
gridRef.current.instance.option('dataSource', dataSource)
|
||
gridRef.current.instance.option('state', null)
|
||
|
||
const stateStoring: IStateStoringProps = {
|
||
enabled: gridDto?.gridOptions.stateStoringDto?.enabled,
|
||
type: gridDto?.gridOptions.stateStoringDto?.type,
|
||
savingTimeout: gridDto?.gridOptions.stateStoringDto?.savingTimeout,
|
||
storageKey: gridDto?.gridOptions.stateStoringDto?.storageKey,
|
||
}
|
||
if (
|
||
gridDto?.gridOptions.stateStoringDto?.enabled &&
|
||
gridDto?.gridOptions.stateStoringDto?.type === 'custom'
|
||
) {
|
||
stateStoring.customSave = customSaveState
|
||
stateStoring.customLoad = customLoadState
|
||
}
|
||
gridRef.current.instance.option('stateStoring', stateStoring)
|
||
|
||
//chart Integration
|
||
if (gridRef && chartRef) {
|
||
gridRef?.current?.instance.bindChart(chartRef?.current?.instance, {
|
||
dataFieldsDisplayMode: 'splitPanes',
|
||
alternateDataFields: false,
|
||
})
|
||
}
|
||
}, [columnData])
|
||
|
||
return (
|
||
<>
|
||
<WidgetGroup widgetGroups={gridDto?.widgets ?? []} />
|
||
|
||
<Container className={DX_CLASSNAMES}>
|
||
{!isSubForm && (
|
||
<Helmet
|
||
titleTemplate="%s | Sözsoft Kurs Platform"
|
||
title={translate('::' + gridDto?.gridOptions.title)}
|
||
defaultTitle="Sözsoft Kurs Platform"
|
||
></Helmet>
|
||
)}
|
||
{gridDto && columnData && (
|
||
<div className="p-1 bg-white dark:bg-neutral-800 dark:border-neutral-700 ">
|
||
<div className="flex justify-end items-center">
|
||
<div className="relative pb-1 flex gap-1 border-b-1">
|
||
<Button
|
||
size="xs"
|
||
variant={'default'}
|
||
className="text-sm"
|
||
onClick={clearPivotFilters}
|
||
title="Remove Filter"
|
||
>
|
||
<FaTimes className="w-3 h-3" />
|
||
</Button>
|
||
|
||
<Button
|
||
size="xs"
|
||
variant={'default'}
|
||
className="text-sm"
|
||
onClick={resetPivotGridState}
|
||
title="Reset Grid State"
|
||
>
|
||
<FaUndo className="w-3 h-3" />
|
||
</Button>
|
||
|
||
{checkPermission(gridDto?.gridOptions.permissionDto.u) && (
|
||
<Button
|
||
size="xs"
|
||
variant={'default'}
|
||
className="text-sm"
|
||
onClick={() => {
|
||
window.open(
|
||
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(
|
||
':listFormCode',
|
||
listFormCode,
|
||
),
|
||
isPwaMode ? '_self' : '_blank',
|
||
)
|
||
}}
|
||
title="Form Manager"
|
||
>
|
||
<FaCog className="w-3 h-3" />
|
||
</Button>
|
||
)}
|
||
</div>
|
||
</div>
|
||
{gridDto.gridOptions.pivotOptionDto.showChart && (
|
||
<Chart ref={chartRef as any}>
|
||
<Size height={gridDto.gridOptions.pivotOptionDto.chartHeight} />
|
||
<Tooltip enabled={true}></Tooltip>
|
||
<CommonSeriesSettings
|
||
type={gridDto.gridOptions.pivotOptionDto.chartCommonSeriesType}
|
||
/>
|
||
</Chart>
|
||
)}
|
||
|
||
<div className="dx-datagrid-header-panel h-1"></div>
|
||
|
||
<PivotGrid
|
||
ref={gridRef as any}
|
||
id={'Pivot-' + listFormCode}
|
||
allowFiltering={gridDto.gridOptions.filterRowDto.visible}
|
||
allowSorting={gridDto.gridOptions.sortMode !== 'none'}
|
||
allowSortingBySummary={gridDto.gridOptions.sortMode !== 'none'}
|
||
height={gridDto.gridOptions.height || '100%'}
|
||
width={gridDto.gridOptions.width || '100%'}
|
||
showBorders={gridDto.gridOptions.columnOptionDto?.showBorders}
|
||
rtlEnabled={gridDto.gridOptions.columnOptionDto?.rtlEnabled}
|
||
hoverStateEnabled={gridDto.gridOptions.columnOptionDto?.hoverStateEnabled}
|
||
onCellPrepared={onCellPrepared}
|
||
>
|
||
<HeaderFilter
|
||
allowSelectAll={gridDto.gridOptions.selectionDto.allowSelectAll}
|
||
width={gridDto.gridOptions.headerFilterDto.width}
|
||
height={gridDto.gridOptions.headerFilterDto.height}
|
||
>
|
||
<Search
|
||
enabled={gridDto.gridOptions.headerFilterDto.allowSearch}
|
||
timeout={gridDto.gridOptions.headerFilterDto.searchTimeout}
|
||
></Search>
|
||
</HeaderFilter>
|
||
<FieldPanel
|
||
allowFieldDragging={gridDto.gridOptions.pivotOptionDto.allowFieldDragging}
|
||
visible={gridDto.gridOptions.pivotOptionDto.showFieldPanel}
|
||
showDataFields={gridDto.gridOptions.pivotOptionDto.showDataFields}
|
||
showColumnFields={gridDto.gridOptions.pivotOptionDto.showColumnFields}
|
||
showRowFields={gridDto.gridOptions.pivotOptionDto.showRowFields}
|
||
showFilterFields={gridDto.gridOptions.pivotOptionDto.showFilterFields}
|
||
/>
|
||
<FieldChooser
|
||
enabled={gridDto.gridOptions.pivotOptionDto.columnChooserEnabled}
|
||
height={500}
|
||
/>
|
||
<Scrolling mode={gridDto.gridOptions.pagerOptionDto.scrollingMode} />
|
||
</PivotGrid>
|
||
</div>
|
||
)}
|
||
</Container>
|
||
</>
|
||
)
|
||
}
|
||
|
||
export default Pivot
|
||
|
||
/*
|
||
<Toolbar visible={toolbarData.length > 0 || filterToolbarData.length > 0}>
|
||
{toolbarData.map((item) => (
|
||
<Item key={item.name} {...item}></Item>
|
||
))}
|
||
{filterToolbarData.map((item) => (
|
||
<Item key={item.name} {...item}></Item>
|
||
))}
|
||
</Toolbar>
|
||
<Sorting mode={gridDto.gridOptions?.sortMode}></Sorting>
|
||
<FilterRow
|
||
visible={gridDto.gridOptions.filterRowDto?.visible}
|
||
applyFilter={gridDto.gridOptions.filterRowDto?.applyFilter}
|
||
></FilterRow>
|
||
<FilterPanel visible={gridDto.gridOptions.filterPanelDto.visible}></FilterPanel>
|
||
<HeaderFilter visible={gridDto.gridOptions.headerFilterDto.visible}></HeaderFilter>
|
||
<SearchPanel
|
||
visible={gridDto.gridOptions.searchPanelDto.visible}
|
||
width={gridDto.gridOptions.searchPanelDto.width}
|
||
></SearchPanel>
|
||
<GroupPanel visible={gridDto.gridOptions.groupPanelDto?.visible}></GroupPanel>
|
||
<Grouping autoExpandAll={gridDto.gridOptions.groupPanelDto?.autoExpandAll}></Grouping>
|
||
<Selection
|
||
mode={gridDto.gridOptions.selectionDto?.mode}
|
||
allowSelectAll={gridDto.gridOptions.selectionDto?.allowSelectAll}
|
||
selectAllMode={gridDto.gridOptions.selectionDto?.selectAllMode}
|
||
showCheckBoxesMode={gridDto.gridOptions.selectionDto?.showCheckBoxesMode}
|
||
></Selection>
|
||
<Pager
|
||
visible={gridDto.gridOptions.pagerOptionDto?.visible}
|
||
allowedPageSizes={gridDto.gridOptions.pagerOptionDto?.allowedPageSizes
|
||
?.split(',')
|
||
.map((a) => +a)}
|
||
showPageSizeSelector={gridDto.gridOptions.pagerOptionDto?.showPageSizeSelector}
|
||
showInfo={gridDto.gridOptions.pagerOptionDto?.showInfo}
|
||
showNavigationButtons={gridDto.gridOptions.pagerOptionDto?.showNavigationButtons}
|
||
infoText={gridDto.gridOptions.pagerOptionDto?.infoText}
|
||
displayMode={gridDto.gridOptions.pagerOptionDto?.displayMode}
|
||
></Pager>
|
||
<ColumnChooser
|
||
enabled={gridDto.gridOptions.columnOptionDto?.columnChooserEnabled}
|
||
mode={gridDto.gridOptions.columnOptionDto?.columnChooserMode}
|
||
></ColumnChooser>
|
||
<ColumnFixing
|
||
enabled={gridDto.gridOptions.columnOptionDto?.columnFixingEnabled}
|
||
></ColumnFixing>
|
||
<Scrolling mode={gridDto.gridOptions.pagerOptionDto?.scrollingMode}></Scrolling>
|
||
<LoadPanel
|
||
enabled={gridDto.gridOptions.pagerOptionDto?.loadPanelEnabled}
|
||
text={gridDto.gridOptions.pagerOptionDto?.loadPanelText}
|
||
></LoadPanel>
|
||
*/
|