erp-platform/ui/src/views/form/useGridData.tsx
2025-08-12 22:42:32 +03:00

318 lines
9.9 KiB
TypeScript

import { Notification, toast } from '@/components/ui'
import { getList } from '@/services/form.service'
import { useListFormColumns } from '@/shared/useListFormColumns'
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { usePermission } from '@/utils/hooks/usePermission'
import { Form as FormDx } from 'devextreme-react/form'
import { captionize } from 'devextreme/core/utils/inflector'
import CustomStore from 'devextreme/data/custom_store'
import { GroupItem } from 'devextreme/ui/form'
import { useEffect, useRef, useState } from 'react'
import { useNavigate, useSearchParams } from 'react-router-dom'
import { GridColumnData } from '../list/GridColumnData'
import { addCss, addJs } from '../list/Utils'
import { PermissionResults, RowMode, SimpleItemWithColData } from './types'
import { EditingFormItemDto, GridDto, PlatformEditorTypes } from '@/proxy/form/models'
import { getAccessDeniedPath } from '@/utils/routing'
const useGridData = (props: {
mode: RowMode
listFormCode: string
id?: string
level?: number
isSubForm?: boolean
onSubmitAction?: () => void
}) => {
const { mode, listFormCode, id, isSubForm } = props
const [gridReady, setGridReady] = useState(false)
const [loading, setLoading] = useState(false)
const [filter, setFilter] = useState<any[]>([])
const [gridDto, setGridDto] = useState<GridDto>()
const [dataSource, setDataSource] = useState<CustomStore<any, any>>()
const [commandColumnData, setCommandColumnData] = useState<GridColumnData>()
const [formDataOld, setFormDataOld] = useState<any>()
const [formData, setFormData] = useState<any>()
const [formItems, setFormItems] = useState<GroupItem[]>([])
const [permissionResults, setPermissionResults] = useState<PermissionResults>()
const refForm = useRef<FormDx>(null)
const [searchParams] = useSearchParams()
const navigate = useNavigate()
const { translate } = useLocalization()
const { checkPermission } = usePermission()
const { getBandedColumns } = useListFormColumns({
gridDto,
listFormCode,
isSubForm,
})
const { createSelectDataSource } = useListFormCustomDataSource({})
const fetchData = async () => {
setLoading(true)
try {
const response: any = await dataSource?.load({
filter,
skip: 0,
take: 1,
})
if (response?.data?.length) {
setFormData(response.data[0])
setFormDataOld({ ...response.data[0] })
} else {
setFormData(undefined)
setFormDataOld(undefined)
}
} catch (error: any) {
toast.push(<Notification title={error.message} type="danger" />, {
placement: 'top-center',
})
} finally {
setLoading(false)
}
}
const handleSubmit = async (e: any) => {
e.preventDefault()
if (!dataSource) {
return
}
const validationResult = refForm.current?.instance.validate()
if (!validationResult?.isValid) {
return
}
setLoading(true)
try {
const formValues = { ...formData }
if (mode === 'new') {
const result = await dataSource.insert(formValues)
if (result.data) {
if (!isSubForm) {
navigate(result.data)
} else if (props.onSubmitAction) {
props.onSubmitAction()
}
toast.push(
<Notification type="success" duration={2000}>
{translate('::ListForms.FormBilgileriKaydedildi')}
</Notification>,
{
placement: 'top-center',
},
)
} else {
throw new Error(translate('::ListForms.FormBilgileriKaydedilemedi'))
}
} else if (mode === 'edit') {
let data: any = {}
if (gridDto?.gridOptions.editingOptionDto?.sendOnlyChangedFormValuesUpdate) {
Object.keys(formValues).forEach((key) => {
if (formValues[key] !== formDataOld[key]) {
data[key] = formValues[key]
}
})
} else {
data = { ...formValues }
}
if (gridDto?.gridOptions.keyFieldName) {
delete data[gridDto?.gridOptions.keyFieldName]
}
var result = await dataSource.update(id, data)
if (result.data > 0) {
if (!isSubForm) {
navigate(`/form/${listFormCode}/${id}`)
} else if (props.onSubmitAction) {
props.onSubmitAction()
}
toast.push(
<Notification type="success" duration={2000}>
{translate('::ListForms.FormBilgileriKaydedildi')}
</Notification>,
{
placement: 'top-center',
},
)
} else {
throw new Error(translate('::ListForms.FormBilgileriKaydedilemedi'))
}
}
} catch (error: any) {
toast.push(<Notification title={error.message} type="danger" />, {
placement: 'top-center',
})
} finally {
setLoading(false)
}
}
useEffect(() => {
setGridReady(false)
const initializeGrid = async () => {
const response = await getList({ listFormCode })
setGridDto(response.data)
}
initializeGrid()
}, [listFormCode])
useEffect(() => {
setGridReady(false)
if (!gridDto) {
return
}
setPermissionResults({
c:
gridDto?.gridOptions.editingOptionDto.allowAdding === true &&
checkPermission(gridDto?.gridOptions.permissionDto.c),
r: checkPermission(gridDto?.gridOptions.permissionDto.r),
u:
gridDto?.gridOptions.editingOptionDto.allowUpdating === true &&
checkPermission(gridDto?.gridOptions.permissionDto.u),
d:
gridDto?.gridOptions.editingOptionDto.allowDeleting === true &&
checkPermission(gridDto?.gridOptions.permissionDto.d),
e: checkPermission(gridDto?.gridOptions.permissionDto.e),
})
// Set js and css
const grdOpt = gridDto.gridOptions
grdOpt.customJsSources.forEach(addJs)
grdOpt.customStyleSources.forEach(addCss)
// Set columns
const cols = getBandedColumns()
setCommandColumnData(cols?.find((a) => a.type == 'buttons'))
// Set data source
const dataSource: CustomStore<any, any> = createSelectDataSource(
gridDto.gridOptions,
listFormCode,
searchParams,
cols,
)
setDataSource(dataSource)
const items = gridDto?.gridOptions.editingFormDto
?.sort((a: any, b: any) => {
return a.order >= b.order ? 1 : -1
})
.map((e: any) => {
return {
itemType: e.itemType,
colCount: e.colCount,
colSpan: e.colSpan,
caption: e.caption,
items: e.items
?.sort((a: any, b: any) => {
return a.order >= b.order ? 1 : -1
})
.map((i: EditingFormItemDto) => {
let editorOptions = {}
try {
editorOptions = i.editorOptions && JSON.parse(i.editorOptions)
} catch {}
const item: SimpleItemWithColData = {
canRead:
gridDto.columnFormats.find((x: any) => x.fieldName === i.dataField)?.canRead ??
false,
canUpdate:
gridDto.columnFormats.find((x: any) => x.fieldName === i.dataField)?.canUpdate ??
false,
canCreate:
gridDto.columnFormats.find((x: any) => x.fieldName === i.dataField)?.canCreate ??
false,
canExport:
gridDto.columnFormats.find((x: any) => x.fieldName === i.dataField)?.canExport ??
false,
dataField: i.dataField,
name: i.dataField,
editorType2: i.editorType2,
editorType:
i.editorType2 == PlatformEditorTypes.dxGridBox ? 'dxDropDownBox' : i.editorType2,
colSpan: i.colSpan,
isRequired: i.isRequired,
editorOptions,
colData: cols?.find((x) => x.dataField === i.dataField),
tagBoxOptions: i.tagBoxOptions,
gridBoxOptions: i.gridBoxOptions,
}
if (i.dataField.indexOf(':') >= 0) {
item.label = { text: captionize(i.dataField.split(':')[1]) }
}
if ((mode == 'edit' && !item.canUpdate) || (mode == 'new' && !item.canCreate)) {
item.editorOptions = {
...item.editorOptions,
readOnly: true,
}
}
return item
})
.filter((a: any) => {
if (mode === 'view') {
return a.canRead
} else if (mode === 'new') {
return a.canCreate || a.canRead
} else if (mode === 'edit') {
return a.canUpdate || a.canRead
} else {
return false
}
}),
} as GroupItem
})
setFormItems(items)
setGridReady(true)
}, [gridDto])
useEffect(() => {
if (!gridReady) {
return
}
if (mode !== 'new') {
setFilter([gridDto?.gridOptions.keyFieldName ?? 'Id', '=', id])
}
}, [id, gridReady])
useEffect(() => {
if (filter?.length) {
fetchData()
}
}, [filter])
// Auth check
useEffect(() => {
if (!permissionResults) return
const noCreate = mode === 'new' && !permissionResults.c
const noUpdate = mode === 'edit' && !permissionResults.u
const noRead = mode === 'view' && !permissionResults.r
if (noCreate || noUpdate || noRead) {
navigate(getAccessDeniedPath(location.pathname), { replace: true, state: { from: location } })
}
}, [permissionResults])
return {
loading,
gridDto,
dataSource,
commandColumnData,
filter,
formItems,
formData,
refForm,
permissionResults,
fetchData,
setFormData,
handleSubmit,
}
}
export { useGridData }