import { DataGridRef } from 'devextreme-react/data-grid' import { PivotGridRef } from 'devextreme-react/pivot-grid' import CustomStore from 'devextreme/data/custom_store' import { MutableRefObject, useCallback } from 'react' import { layoutTypes, ListViewLayoutType } from '@/views/admin/listForm/edit/types' import { getLoadOptions, getServiceAddress, setGridPanelColor } from './Utils' import { GridOptionsDto } from '@/proxy/form/models' import { GridColumnData } from './GridColumnData' import { dynamicFetch } from '@/services/form.service' import { MULTIVALUE_DELIMITER } from '@/constants/app.constant' import { TreeListRef } from 'devextreme-react/cjs/tree-list' import { GanttRef } from 'devextreme-react/cjs/gantt' import { SchedulerRef } from 'devextreme-react/cjs/scheduler' import { CardViewRef, CardViewTypes } from 'devextreme-react/cjs/card-view' const filteredGridPanelColor = 'rgba(10, 200, 10, 0.5)' // kullanici tanimli filtre ile filtrelenmis gridin paneline ait renk const useListFormCustomDataSource = ({ gridRef, }: { gridRef: | MutableRefObject | undefined> | MutableRefObject | MutableRefObject | undefined> | MutableRefObject | MutableRefObject | MutableRefObject }) => { const createSelectDataSource = useCallback( ( gridOptions: GridOptionsDto, listFormCode: string, searchParams?: URLSearchParams, layout?: ListViewLayoutType | string, cols?: GridColumnData[] | CardViewTypes.Column[], ) => { const store: any = new CustomStore({ key: layout === layoutTypes.tree ? gridOptions.treeOptionDto?.keyExpr : gridOptions.keyFieldName, useDefaultSearch: true, load: async (loadOptions) => { // URL'den sort parametresini al ve loadOptions'a ekle const urlSort = searchParams?.get('sort') if (urlSort && !loadOptions.sort) { try { loadOptions.sort = JSON.parse(urlSort) } catch (e) { console.error('Sort parse error:', e) } } const parameters = getLoadOptions(loadOptions, { listFormCode, filter: '', createDeleteQuery: searchParams?.get('createDeleteQuery'), chart: layout === layoutTypes.chart, }) // Chart için group ve groupSummary parametreleri ekle if (layout === layoutTypes.chart && gridOptions.seriesDto && gridOptions.seriesDto.length > 0) { // Tüm series'lerin unique argumentField'larını topla const allArgumentFields = [...new Set(gridOptions.seriesDto.map(s => s.argumentField).filter(Boolean))] as string[] // İlk argumentField üzerinden group yap (chart tek bir X ekseni kullanır) if (allArgumentFields.length > 0) { loadOptions.group = allArgumentFields.map(field => ({ selector: field as string, isExpanded: false })) } // Tüm series'lerin valueField'ları için summary hesapla const groupSummaries: any[] = [] gridOptions.seriesDto.forEach(series => { if (series.valueField && series.summaryType) { groupSummaries.push({ selector: series.valueField, summaryType: series.summaryType as any }) } }) if (groupSummaries.length > 0) { loadOptions.groupSummary = groupSummaries } // Parametreleri tekrar oluştur const chartParameters = getLoadOptions(loadOptions, { listFormCode, filter: '', createDeleteQuery: searchParams?.get('createDeleteQuery'), chart: layout === layoutTypes.chart, }) Object.assign(parameters, chartParameters) } // 1. Default filter'ı al const defaultFilter = searchParams?.get('filter') ? JSON.parse(searchParams.get('filter')!) : null let combinedFilter: any = parameters.filter // 2. Eğer hem default hem de grid filter varsa merge et if (defaultFilter && combinedFilter) { combinedFilter = [defaultFilter, 'and', combinedFilter] } else if (defaultFilter) { combinedFilter = defaultFilter } //editing asamasinda her bir field de yapilan degisiklik load istegi olarak buraya dusuyor. //TODO: bu bug halen devam ediyor!! //Bunu engellemek icin eklendi. //if (!params.hasOwnProperty('requireTotalCount')) { // return; //} try { if (gridRef?.current) { //TODO: } // Type guard to handle union type for gridRef let columns = cols if (gridRef?.current?.instance()) { const instance = gridRef?.current?.instance() as any const instanceColumns = instance.option('columns') if (instanceColumns) { columns = instanceColumns as GridColumnData[] } } // URL'deki filtreyi grid'in mevcut filtrelerinin üzerine uygula if (columns?.length && searchParams) { const filters: (string[] | string)[] = [] for (const col of columns) { if (col.dataField) { const sValue = searchParams.get(col.dataField) if (sValue) { filters.push([col.dataField, '=', sValue]) filters.push('and') } } } if (filters.length) { filters.pop() // son and'i sil if (parameters.filter) { parameters.filter = [...parameters.filter, 'and', ...filters] } else { parameters.filter = filters } } } if (combinedFilter && combinedFilter.length > 0) { parameters.filter = JSON.stringify(combinedFilter) } else { delete parameters.filter // hiç göndermesin } //parameters.filter = JSON.stringify(parameters.filter) const response = await dynamicFetch('list-form-select/select', 'GET', parameters) // Chart için grouped data'yı chart formatına çevir if (layout === layoutTypes.chart && Array.isArray(response.data.data)) { const flattenGroupedData = (items: any[], parentKeys: any = {}): any[] => { const result: any[] = [] items.forEach((item: any) => { if (item.items && item.items.length > 0) { // Alt grup var, recursive olarak işle const currentKeys = { ...parentKeys } // Bu level'daki key'i ilgili argumentField'a map'le gridOptions.seriesDto?.forEach(series => { if (series.argumentField && !currentKeys[series.argumentField]) { currentKeys[series.argumentField] = item.key } }) result.push(...flattenGroupedData(item.items, currentKeys)) } else { // Leaf node - gerçek data const transformed: any = { ...parentKeys } // Son level'daki key'i ekle gridOptions.seriesDto?.forEach(series => { if (series.argumentField && item.key !== undefined && !transformed[series.argumentField]) { transformed[series.argumentField] = item.key } }) // Summary değerlerini valueField'lara map'le if (Array.isArray(item.summary)) { gridOptions.seriesDto?.forEach((series, index) => { if (series.valueField && item.summary[index] !== undefined) { transformed[series.valueField] = item.summary[index] } }) } result.push(transformed) } }) return result } response.data.data = flattenGroupedData(response.data.data) } // Column format multiValue ise, gelen stringi array yapmaliyiz if (columns) { columns.forEach((col: any) => { // Column multiValue mu? if (col.extras?.multiValue) { //console.log('MultiValue:', col.dataField, col.extras?.multiValue) // Multivalue column icin header filter acildiginda gonderilen group querysi sonuclari // "key" field ile geliyor, bunu array yapmamiz lazim, bu group query'nin, // bu field icin olup olmadigini anlayabiliriz const isGroupQuery = parameters?.group?.includes(col.dataField) response.data.data?.forEach((row: any) => { try { if (row[col.dataField]) { // value'yu arraye cevir row[col.dataField] = row[col.dataField]?.split(MULTIVALUE_DELIMITER) } if (isGroupQuery && row.key) { // group query sonucunda gelen key'i arraye cevir row.key = row.key.split(MULTIVALUE_DELIMITER) } } catch (e) { // toast.push( // // {'multiValue Error'} // , // { // placement: 'top-end', // }, // ) console.log('multiValue Error', e) // JSON parse sirasinde hata olursa data gosterimi devam etsin } }) } }) //TODO: Bu neden var? Eğer gerekli değilse kaldırılabilir. searchParams?.set('createDeleteQuery', 'false') } // gride filtre uygulanmis ise renklendir setGridPanelColor( response.data.queryInfos?.isAppliedGridFilter ? filteredGridPanelColor : 'transparent', ) const retValue = { data: response.data.data, totalCount: response.data.totalCount, summary: response.data.summary, groupCount: response.data.groupCount, } return retValue } catch (error: any) { // toast.push( // // Select error // {error.toString()} // , // { // placement: 'top-end', // }, // ) return null } }, // totalCount: async (loadOptions) => { // const parameters = getLoadOptions(loadOptions, { // listFormCode, // filter: '', // createDeleteQuery: searchParams?.get('createDeleteQuery'), // group: '', // }) // // 1. Default filter'ı al // const defaultFilter = searchParams?.get('filter') // ? JSON.parse(searchParams.get('filter')!) // : null // let combinedFilter: any = parameters.filter // // 2. Eğer hem default hem de grid filter varsa merge et // if (defaultFilter && combinedFilter) { // combinedFilter = [defaultFilter, 'and', combinedFilter] // } else if (defaultFilter) { // combinedFilter = defaultFilter // } // if (combinedFilter && combinedFilter.length > 0) { // parameters.filter = JSON.stringify(combinedFilter) // } else { // delete parameters.filter // hiç göndermesin // } // try { // const response = await dynamicFetch('list-form-select/select', 'GET', parameters) // return response.data.totalCount // } catch (error: any) { // // toast.push( // // // // TotalCount error // // {error.toString()} // // , // // { // // placement: 'top-end', // // }, // // ) // return null // } // }, byKey: async (key) => { const parameters = getLoadOptions( { key }, { listFormCode, filter: '', createDeleteQuery: '' }, ) parameters.filter = JSON.stringify(parameters.filter) try { const response = await dynamicFetch('list-form-select/select', 'GET', parameters) return response.data.data[0] } catch (error: any) { // toast.push( // // ByKey error // {error.toString()} // , // { // placement: 'top-end', // }, // ) return null } }, remove: function (key) { if (!gridOptions.deleteServiceAddress) { return } const deleteUrl = getServiceAddress(gridOptions.deleteServiceAddress) return dynamicFetch(deleteUrl, 'POST', searchParams, { keys: [key], listFormCode, }) }, update: function (key, values) { if (!gridOptions.updateServiceAddress) { return } const updateUrl = getServiceAddress(gridOptions.updateServiceAddress) return dynamicFetch(updateUrl, 'POST', searchParams, { keys: [key], data: values, listFormCode, }) }, insert: function (values) { if (!gridOptions.insertServiceAddress) { return } const insertUrl = getServiceAddress(gridOptions.insertServiceAddress) return dynamicFetch(insertUrl, 'POST', searchParams, { data: values, listFormCode }) }, errorHandler: (error: any) => { console.log(error.message) }, }) return store }, [], ) return { createSelectDataSource, } } export { useListFormCustomDataSource }