erp-platform/ui/src/views/form/useFormData.tsx
2025-11-11 15:00:52 +03:00

371 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Notification, toast } from '@/components/ui'
import { getList } from '@/services/form.service'
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'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { useLookupDataSource } from './useLookupDataSource'
import { layoutTypes } from '../admin/listForm/edit/types'
import { useListFormCustomDataSource } from '../list/useListFormCustomDataSource'
import { useListFormColumns } from '../list/useListFormColumns'
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,
gridRef: undefined,
})
const { createSelectDataSource } = useListFormCustomDataSource({} as any)
const { getLookupDataSource } = useLookupDataSource({ listFormCode, isSubForm })
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-end',
})
} 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-end',
},
)
} 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(
ROUTES_ENUM.protected.admin.formView
.replace(':listFormCode', listFormCode)
.replace(':id', id!),
)
} else if (props.onSubmitAction) {
props.onSubmitAction()
}
toast.push(
<Notification type="success" duration={2000}>
{translate('::ListForms.FormBilgileriKaydedildi')}
</Notification>,
{
placement: 'top-end',
},
)
} else {
throw new Error(translate('::ListForms.FormBilgileriKaydedilemedi'))
}
}
} catch (error: any) {
toast.push(<Notification title={error.message} type="danger" />, {
placement: 'top-end',
})
} 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),
i: checkPermission(gridDto?.gridOptions.permissionDto.i),
})
// 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,
layoutTypes.grid,
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 = {}
const colData = gridDto.columnFormats.find((x) => x.fieldName === i.dataField)
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: {
...editorOptions,
...(colData?.lookupDto?.dataSourceType
? {
dataSource: getLookupDataSource(colData?.editorOptions, colData, formData),
valueExpr: colData?.lookupDto?.valueExpr?.toLowerCase(),
displayExpr: colData?.lookupDto?.displayExpr?.toLowerCase(),
}
: {}),
},
colData,
tagBoxOptions: i.tagBoxOptions,
gridBoxOptions: i.gridBoxOptions,
editorScript: i.editorScript,
}
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])
// formData değiştiğinde sadece lookup datasource'ları güncelle
useEffect(() => {
if (!gridDto || !formItems.length) {
return
}
// View mode'da formData olsa da olmasa da cascading alanlar için dataSource oluşturulmalı
const updatedItems = formItems.map((groupItem) => ({
...groupItem,
items: (groupItem.items as SimpleItemWithColData[])?.map((item) => {
const colData = gridDto.columnFormats.find((x) => x.fieldName === item.dataField)
if (colData?.lookupDto?.dataSourceType) {
return {
...item,
editorOptions: {
...item.editorOptions,
// formData null bile olsa getLookupDataSource çağrılmalı (null parametrelerle API çağrısı yapılacak)
dataSource: getLookupDataSource(colData?.editorOptions, colData, formData || null),
valueExpr: colData?.lookupDto?.valueExpr?.toLowerCase(),
displayExpr: colData?.lookupDto?.displayExpr?.toLowerCase(),
},
}
}
return item
}),
}))
setFormItems(updatedItems)
}, [formData, 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 }