371 lines
12 KiB
TypeScript
371 lines
12 KiB
TypeScript
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 }
|