sozsoft-platform/ui/src/views/form/FormButtons.tsx
2026-09-07 09:14:00 +03:00

365 lines
9.7 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'
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
}) => {
const {
isSubForm,
mode,
listFormCode,
id,
gridDto,
commandColumnData,
dataSource,
permissions,
handleSubmit,
refreshData,
getSelectedRowKeys,
getSelectedRowsData,
getFilter,
onActionEdit,
onActionNew,
onActionView,
} = props
const [deleteRowId, setDeleteRowId] = useState<string>()
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 (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} />
<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