389 lines
11 KiB
TypeScript
389 lines
11 KiB
TypeScript
import { Button, Dialog, Notification, toast } from '@/components/ui'
|
||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||
import CustomStore from 'devextreme/data/custom_store'
|
||
import Toolbar from 'devextreme-react/toolbar'
|
||
import type { dxToolbarItem as DxToolbarItem } from 'devextreme/ui/toolbar'
|
||
import { useState } from 'react'
|
||
import { useNavigate } from 'react-router-dom'
|
||
import { GridColumnData } from '../list/GridColumnData'
|
||
import { isWorkflowToolbarItemDisabled, useToolbar } from '../list/useToolbar'
|
||
import { orderListToolbarItems } from '../list/toolbarOrder'
|
||
import { PermissionResults, RowMode } from './types'
|
||
import { GridDto } from '@/proxy/form/models'
|
||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||
import { usePermission } from '@/utils/hooks/usePermission'
|
||
import { usePWA } from '@/utils/hooks/usePWA'
|
||
import { layoutTypes } from '../admin/listForm/edit/types'
|
||
import { useStoreState } from '@/store'
|
||
import FormFieldOrderPanel from './FormFieldOrderPanel'
|
||
import type { FormFieldOrder } from './shared/formItems'
|
||
|
||
/** Form sayfasının kullanıcı bazlı alan sırası (`useGridData`). */
|
||
type FormFieldOrderControl = {
|
||
value?: FormFieldOrder
|
||
preview: (order: FormFieldOrder | undefined) => void
|
||
save: (order: FormFieldOrder | undefined) => Promise<void>
|
||
}
|
||
|
||
const FormButtons = (props: {
|
||
isSubForm?: boolean
|
||
mode: RowMode
|
||
listFormCode: string
|
||
id?: string
|
||
gridDto: GridDto
|
||
commandColumnData: GridColumnData
|
||
dataSource: CustomStore<any, any>
|
||
permissions: PermissionResults
|
||
handleSubmit: (e: any) => void
|
||
refreshData: () => void
|
||
getSelectedRowKeys: () => any[] | Promise<any[]>
|
||
getSelectedRowsData: () => any[]
|
||
getFilter: () => void
|
||
onActionEdit?: () => void
|
||
onActionNew?: () => void
|
||
onActionView?: () => void
|
||
/** Verilirse araç çubuğunda alan sırası paneli açılır (ekranda state saklama açıksa). */
|
||
fieldOrder?: FormFieldOrderControl
|
||
}) => {
|
||
const {
|
||
isSubForm,
|
||
mode,
|
||
listFormCode,
|
||
id,
|
||
gridDto,
|
||
commandColumnData,
|
||
dataSource,
|
||
permissions,
|
||
handleSubmit,
|
||
refreshData,
|
||
getSelectedRowKeys,
|
||
getSelectedRowsData,
|
||
getFilter,
|
||
onActionEdit,
|
||
onActionNew,
|
||
onActionView,
|
||
fieldOrder,
|
||
} = props
|
||
|
||
const [deleteRowId, setDeleteRowId] = useState<string>()
|
||
const [fieldOrderOpen, setFieldOrderOpen] = useState(false)
|
||
const { checkPermission } = usePermission()
|
||
const isPwaMode = usePWA()
|
||
|
||
const navigate = useNavigate()
|
||
const { translate } = useLocalization()
|
||
|
||
const layout = layoutTypes.grid
|
||
const { toolbarData, toolbarModalData, setToolbarModalData } = useToolbar({
|
||
gridDto,
|
||
listFormCode,
|
||
getSelectedRowKeys,
|
||
getSelectedRowsData,
|
||
refreshData,
|
||
getFilter,
|
||
layout,
|
||
})
|
||
|
||
const currentUser = useStoreState((state) => state.auth.user)
|
||
const selectedRowData = getSelectedRowsData()?.[0]
|
||
const rowEvent = {
|
||
row: {
|
||
data: selectedRowData,
|
||
key: id,
|
||
rowType: 'data',
|
||
isEditing: mode === 'edit',
|
||
},
|
||
}
|
||
|
||
const resolveVisible = (visible: unknown) => {
|
||
if (typeof visible !== 'function') {
|
||
return visible !== false
|
||
}
|
||
|
||
try {
|
||
return Boolean(visible(rowEvent))
|
||
} catch (error) {
|
||
console.error('Button visibility evaluation error:', error)
|
||
return false
|
||
}
|
||
}
|
||
|
||
const isToolbarButtonVisible = (item: any) =>
|
||
item.widget === 'dxButton' &&
|
||
!toolbarExcludedNames.includes(item.name) &&
|
||
resolveVisible(item.visible) &&
|
||
resolveVisible(item.options?.visible)
|
||
|
||
const isCommandButtonVisible = (item: any) =>
|
||
typeof item !== 'string' &&
|
||
!commandExcludedNames.includes(item.name) &&
|
||
resolveVisible(item.visible)
|
||
|
||
const isToolbarButtonDisabled = (item: any) => {
|
||
const workflowDisabled = isWorkflowToolbarItemDisabled(
|
||
item.name,
|
||
gridDto.gridOptions.workflowDto,
|
||
selectedRowData ? [selectedRowData] : [],
|
||
currentUser,
|
||
)
|
||
|
||
return workflowDisabled ?? Boolean(item.options?.disabled)
|
||
}
|
||
|
||
const openDynamicGridReport = () => {
|
||
if (!id) return
|
||
|
||
const reportUrl = `/admin/reports/DynamicGrid/view/${encodeURIComponent(id)}/${encodeURIComponent(listFormCode)}`
|
||
window.open(reportUrl, isPwaMode ? '_self' : '_blank')
|
||
}
|
||
|
||
const handleDelete = async (e: any) => {
|
||
//auth check
|
||
e.preventDefault()
|
||
if (!dataSource || !id) {
|
||
return
|
||
}
|
||
|
||
try {
|
||
await dataSource.remove(id)
|
||
setDeleteRowId(undefined)
|
||
if (props.onActionNew) {
|
||
props.onActionNew()
|
||
} else {
|
||
navigate(-1)
|
||
}
|
||
toast.push(
|
||
<Notification type="success" duration={2000}>
|
||
{translate('::App.Platform.RecordDeleted')}
|
||
</Notification>,
|
||
{
|
||
placement: 'bottom-end',
|
||
},
|
||
)
|
||
} catch (error: any) {
|
||
toast.push(<Notification title={error.message} type="danger" />, {
|
||
placement: 'bottom-end',
|
||
})
|
||
}
|
||
}
|
||
|
||
const toolbarExcludedNames = ['deleteAllRecords', 'deleteSelectedRecords', 'refreshButton']
|
||
const commandExcludedNames = ['edit', 'delete', 'detail']
|
||
|
||
/** Grid toolbar sozlesmesiyle ayni bicimde bir dxButton ogesi uretir. */
|
||
const buildButtonItem = (
|
||
icon: string,
|
||
text: string,
|
||
onClick: (e: any) => void,
|
||
disabled = false,
|
||
): DxToolbarItem => ({
|
||
location: 'after',
|
||
widget: 'dxButton',
|
||
locateInMenu: 'auto',
|
||
showText: 'always',
|
||
options: { icon, text, hint: text, disabled, onClick },
|
||
})
|
||
|
||
const toolbarItems: DxToolbarItem[] = [
|
||
// Liste toolbar'indan gelen ozel butonlar; grid ile ayni sirayi korur.
|
||
...orderListToolbarItems(toolbarData?.filter(isToolbarButtonVisible) ?? []).map(
|
||
(item): DxToolbarItem => ({
|
||
location: 'after',
|
||
widget: 'dxButton',
|
||
locateInMenu: 'auto',
|
||
showText: 'always',
|
||
options: {
|
||
...item.options,
|
||
// Gorunurluk zaten filtrelendi; DX'e fonksiyon gecilmemeli.
|
||
visible: true,
|
||
disabled: isToolbarButtonDisabled(item),
|
||
onClick: (e: any) => item.options?.onClick?.({ ...e, ...rowEvent }),
|
||
},
|
||
}),
|
||
),
|
||
|
||
// Komut kolonundan toolbar'a tasinan butonlar.
|
||
...(commandColumnData?.buttons?.filter(isCommandButtonVisible) ?? []).map(
|
||
(item: any): DxToolbarItem => ({
|
||
location: 'after',
|
||
widget: 'dxButton',
|
||
locateInMenu: 'auto',
|
||
showText: 'always',
|
||
options: {
|
||
icon: item.icon,
|
||
text: item.text,
|
||
hint: item.hint ?? item.text,
|
||
onClick: (e: any) => item.onClick?.({ ...e, ...rowEvent }),
|
||
},
|
||
}),
|
||
),
|
||
]
|
||
|
||
if (!isSubForm) {
|
||
toolbarItems.push(
|
||
buildButtonItem('back', translate('::App.Platform.Cancel'), () => {
|
||
if (onActionView && id) {
|
||
onActionView()
|
||
} else {
|
||
navigate(-1)
|
||
}
|
||
}),
|
||
)
|
||
}
|
||
|
||
if (mode !== 'new') {
|
||
toolbarItems.push(
|
||
buildButtonItem(
|
||
'trash',
|
||
translate('::App.Platform.Delete'),
|
||
() => setDeleteRowId(id),
|
||
!permissions.d,
|
||
),
|
||
buildButtonItem(
|
||
'add',
|
||
translate('::App.Platform.AddNew'),
|
||
() => {
|
||
if (onActionNew) {
|
||
onActionNew()
|
||
} else {
|
||
navigate(
|
||
ROUTES_ENUM.protected.admin.formNew.replace(
|
||
':listFormCode',
|
||
encodeURIComponent(listFormCode),
|
||
),
|
||
)
|
||
}
|
||
},
|
||
!permissions.c,
|
||
),
|
||
)
|
||
}
|
||
|
||
if (mode === 'view') {
|
||
toolbarItems.push(
|
||
buildButtonItem(
|
||
'edit',
|
||
translate('::App.Platform.Edit'),
|
||
() => {
|
||
if (onActionEdit) {
|
||
onActionEdit()
|
||
} else {
|
||
navigate(
|
||
ROUTES_ENUM.protected.admin.formEdit
|
||
.replace(':listFormCode', encodeURIComponent(listFormCode))
|
||
.replace(':id', encodeURIComponent(id!)),
|
||
)
|
||
}
|
||
},
|
||
!permissions.u,
|
||
),
|
||
)
|
||
}
|
||
|
||
if (mode === 'edit' || (onActionView && mode === 'new')) {
|
||
toolbarItems.push(
|
||
buildButtonItem(
|
||
'eyeopen',
|
||
translate('::App.Platform.Detail'),
|
||
() => {
|
||
if (onActionView) {
|
||
onActionView()
|
||
} else {
|
||
navigate(
|
||
ROUTES_ENUM.protected.admin.formView
|
||
.replace(':listFormCode', encodeURIComponent(listFormCode))
|
||
.replace(':id', encodeURIComponent(id!)),
|
||
)
|
||
}
|
||
},
|
||
!permissions.r,
|
||
),
|
||
)
|
||
}
|
||
|
||
if (mode === 'edit' || mode === 'new') {
|
||
toolbarItems.push(
|
||
buildButtonItem(
|
||
'save',
|
||
translate('::App.Platform.Save'),
|
||
handleSubmit,
|
||
!(permissions.c || permissions.u),
|
||
),
|
||
)
|
||
}
|
||
|
||
if (id && !isSubForm) {
|
||
toolbarItems.push(
|
||
buildButtonItem('doc', translate('::App.Reports.Form'), openDynamicGridReport),
|
||
)
|
||
}
|
||
|
||
if (fieldOrder) {
|
||
toolbarItems.push(
|
||
buildButtonItem('sorted', translate('::App.ListForm.FormFieldOrder'), () =>
|
||
setFieldOrderOpen(true),
|
||
),
|
||
)
|
||
}
|
||
|
||
if (checkPermission('App.Listforms.Listform.Update') && !isSubForm) {
|
||
toolbarItems.push(
|
||
buildButtonItem('preferences', translate('::App.Platform.Manage'), () => {
|
||
window.open(
|
||
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(':listFormCode', listFormCode),
|
||
isPwaMode ? '_self' : '_blank',
|
||
)
|
||
}),
|
||
)
|
||
}
|
||
|
||
return (
|
||
<>
|
||
<Toolbar className="list-view-toolbar-host flex-1" items={toolbarItems} />
|
||
{fieldOrder && (
|
||
<FormFieldOrderPanel
|
||
isOpen={fieldOrderOpen}
|
||
gridDto={gridDto}
|
||
fieldOrder={fieldOrder.value}
|
||
onClose={() => setFieldOrderOpen(false)}
|
||
onPreview={fieldOrder.preview}
|
||
onSave={fieldOrder.save}
|
||
/>
|
||
)}
|
||
<Dialog
|
||
isOpen={toolbarModalData?.open || false}
|
||
onClose={() => setToolbarModalData(undefined)}
|
||
onRequestClose={() => setToolbarModalData(undefined)}
|
||
>
|
||
{toolbarModalData?.content}
|
||
</Dialog>
|
||
<Dialog
|
||
id="confirmDelete"
|
||
isOpen={!!deleteRowId}
|
||
onClose={() => setDeleteRowId(undefined)}
|
||
onRequestClose={() => setDeleteRowId(undefined)}
|
||
>
|
||
<h5 className="mb-4">{translate('::App.Platform.Delete')}</h5>
|
||
|
||
<p>{translate('::App.Platform.DeleteConfirmation')}</p>
|
||
|
||
<div className="text-right mt-6">
|
||
<Button
|
||
className="ltr:mr-2 rtl:ml-2"
|
||
variant="plain"
|
||
onClick={() => {
|
||
setDeleteRowId(undefined)
|
||
}}
|
||
>
|
||
{translate('::App.Platform.Cancel')}
|
||
</Button>
|
||
<Button variant="solid" onClick={handleDelete}>
|
||
{translate('::App.Platform.Delete')}
|
||
</Button>
|
||
</div>
|
||
</Dialog>
|
||
</>
|
||
)
|
||
}
|
||
|
||
export default FormButtons
|