2026-09-07 06:14:00 +00:00
|
|
|
|
import { Button, Dialog, Notification, toast } from '@/components/ui'
|
2026-02-24 20:44:16 +00:00
|
|
|
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
|
|
|
|
|
import CustomStore from 'devextreme/data/custom_store'
|
2026-09-07 06:14:00 +00:00
|
|
|
|
import Toolbar from 'devextreme-react/toolbar'
|
|
|
|
|
|
import type { dxToolbarItem as DxToolbarItem } from 'devextreme/ui/toolbar'
|
2026-02-24 20:44:16 +00:00
|
|
|
|
import { useState } from 'react'
|
|
|
|
|
|
import { useNavigate } from 'react-router-dom'
|
|
|
|
|
|
import { GridColumnData } from '../list/GridColumnData'
|
2026-07-13 17:29:53 +00:00
|
|
|
|
import { isWorkflowToolbarItemDisabled, useToolbar } from '../list/useToolbar'
|
2026-09-07 06:14:00 +00:00
|
|
|
|
import { orderListToolbarItems } from '../list/toolbarOrder'
|
2026-02-24 20:44:16 +00:00
|
|
|
|
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'
|
2026-07-13 17:29:53 +00:00
|
|
|
|
import { useStoreState } from '@/store'
|
2026-10-06 07:19:26 +00:00
|
|
|
|
import FormFieldOrderPanel from './FormFieldOrderPanel'
|
|
|
|
|
|
import type { FormFieldOrder } from './shared/formItems'
|
|
|
|
|
|
|
|
|
|
|
|
/** Form sayfasının kullanıcı bazlı alan sırası (`useGridData`). */
|
2026-10-07 18:08:10 +00:00
|
|
|
|
type FormFieldOrderControl = {
|
2026-10-06 07:19:26 +00:00
|
|
|
|
value?: FormFieldOrder
|
|
|
|
|
|
preview: (order: FormFieldOrder | undefined) => void
|
|
|
|
|
|
save: (order: FormFieldOrder | undefined) => Promise<void>
|
|
|
|
|
|
}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
|
|
|
|
|
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
|
2026-07-10 08:18:20 +00:00
|
|
|
|
getSelectedRowKeys: () => any[] | Promise<any[]>
|
2026-02-24 20:44:16 +00:00
|
|
|
|
getSelectedRowsData: () => any[]
|
|
|
|
|
|
getFilter: () => void
|
|
|
|
|
|
onActionEdit?: () => void
|
|
|
|
|
|
onActionNew?: () => void
|
|
|
|
|
|
onActionView?: () => void
|
2026-10-06 07:19:26 +00:00
|
|
|
|
/** Verilirse araç çubuğunda alan sırası paneli açılır (ekranda state saklama açıksa). */
|
|
|
|
|
|
fieldOrder?: FormFieldOrderControl
|
2026-02-24 20:44:16 +00:00
|
|
|
|
}) => {
|
|
|
|
|
|
const {
|
|
|
|
|
|
isSubForm,
|
|
|
|
|
|
mode,
|
|
|
|
|
|
listFormCode,
|
|
|
|
|
|
id,
|
|
|
|
|
|
gridDto,
|
|
|
|
|
|
commandColumnData,
|
|
|
|
|
|
dataSource,
|
|
|
|
|
|
permissions,
|
|
|
|
|
|
handleSubmit,
|
|
|
|
|
|
refreshData,
|
|
|
|
|
|
getSelectedRowKeys,
|
|
|
|
|
|
getSelectedRowsData,
|
|
|
|
|
|
getFilter,
|
|
|
|
|
|
onActionEdit,
|
|
|
|
|
|
onActionNew,
|
|
|
|
|
|
onActionView,
|
2026-10-06 07:19:26 +00:00
|
|
|
|
fieldOrder,
|
2026-02-24 20:44:16 +00:00
|
|
|
|
} = props
|
|
|
|
|
|
|
|
|
|
|
|
const [deleteRowId, setDeleteRowId] = useState<string>()
|
2026-10-06 07:19:26 +00:00
|
|
|
|
const [fieldOrderOpen, setFieldOrderOpen] = useState(false)
|
2026-02-24 20:44:16 +00:00
|
|
|
|
const { checkPermission } = usePermission()
|
|
|
|
|
|
const isPwaMode = usePWA()
|
|
|
|
|
|
|
|
|
|
|
|
const navigate = useNavigate()
|
|
|
|
|
|
const { translate } = useLocalization()
|
|
|
|
|
|
|
|
|
|
|
|
const layout = layoutTypes.grid
|
2026-07-13 17:29:53 +00:00
|
|
|
|
const { toolbarData, toolbarModalData, setToolbarModalData } = useToolbar({
|
2026-02-24 20:44:16 +00:00
|
|
|
|
gridDto,
|
|
|
|
|
|
listFormCode,
|
|
|
|
|
|
getSelectedRowKeys,
|
|
|
|
|
|
getSelectedRowsData,
|
|
|
|
|
|
refreshData,
|
|
|
|
|
|
getFilter,
|
|
|
|
|
|
layout,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2026-07-13 17:29:53 +00:00
|
|
|
|
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)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-16 21:19:14 +00:00
|
|
|
|
const openDynamicGridReport = () => {
|
|
|
|
|
|
if (!id) return
|
|
|
|
|
|
|
|
|
|
|
|
const reportUrl = `/admin/reports/DynamicGrid/view/${encodeURIComponent(id)}/${encodeURIComponent(listFormCode)}`
|
|
|
|
|
|
window.open(reportUrl, isPwaMode ? '_self' : '_blank')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 20:44:16 +00:00
|
|
|
|
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}>
|
2026-08-14 14:03:34 +00:00
|
|
|
|
{translate('::App.Platform.RecordDeleted')}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
</Notification>,
|
|
|
|
|
|
{
|
2026-07-08 06:14:40 +00:00
|
|
|
|
placement: 'bottom-end',
|
2026-02-24 20:44:16 +00:00
|
|
|
|
},
|
|
|
|
|
|
)
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
toast.push(<Notification title={error.message} type="danger" />, {
|
2026-07-08 06:14:40 +00:00
|
|
|
|
placement: 'bottom-end',
|
2026-02-24 20:44:16 +00:00
|
|
|
|
})
|
2026-10-06 07:19:26 +00:00
|
|
|
|
}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const toolbarExcludedNames = ['deleteAllRecords', 'deleteSelectedRecords', 'refreshButton']
|
|
|
|
|
|
const commandExcludedNames = ['edit', 'delete', 'detail']
|
|
|
|
|
|
|
2026-09-07 06:14:00 +00:00
|
|
|
|
/** 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)
|
|
|
|
|
|
}
|
|
|
|
|
|
}),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
2026-09-07 06:14:00 +00:00
|
|
|
|
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),
|
|
|
|
|
|
),
|
2026-02-24 20:44:16 +00:00
|
|
|
|
)
|
2026-09-07 06:14:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
!permissions.c,
|
|
|
|
|
|
),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
2026-09-07 06:14:00 +00:00
|
|
|
|
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,
|
|
|
|
|
|
),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
2026-09-07 06:14:00 +00:00
|
|
|
|
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!)),
|
2026-02-24 20:44:16 +00:00
|
|
|
|
)
|
2026-09-07 06:14:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
!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(
|
2026-10-06 07:19:26 +00:00
|
|
|
|
buildButtonItem('doc', translate('::App.Reports.Form'), openDynamicGridReport),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (fieldOrder) {
|
|
|
|
|
|
toolbarItems.push(
|
|
|
|
|
|
buildButtonItem('sorted', translate('::App.ListForm.FormFieldOrder'), () =>
|
|
|
|
|
|
setFieldOrderOpen(true),
|
2026-09-07 06:14:00 +00:00
|
|
|
|
),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
2026-09-07 06:14:00 +00:00
|
|
|
|
if (checkPermission('App.Listforms.Listform.Update') && !isSubForm) {
|
|
|
|
|
|
toolbarItems.push(
|
|
|
|
|
|
buildButtonItem('preferences', translate('::App.Platform.Manage'), () => {
|
|
|
|
|
|
window.open(
|
2026-10-06 07:19:26 +00:00
|
|
|
|
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(':listFormCode', listFormCode),
|
2026-09-07 06:14:00 +00:00
|
|
|
|
isPwaMode ? '_self' : '_blank',
|
|
|
|
|
|
)
|
|
|
|
|
|
}),
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
2026-09-07 06:14:00 +00:00
|
|
|
|
return (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<Toolbar className="list-view-toolbar-host flex-1" items={toolbarItems} />
|
2026-10-06 07:19:26 +00:00
|
|
|
|
{fieldOrder && (
|
|
|
|
|
|
<FormFieldOrderPanel
|
|
|
|
|
|
isOpen={fieldOrderOpen}
|
|
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
|
fieldOrder={fieldOrder.value}
|
|
|
|
|
|
onClose={() => setFieldOrderOpen(false)}
|
|
|
|
|
|
onPreview={fieldOrder.preview}
|
|
|
|
|
|
onSave={fieldOrder.save}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
2026-07-13 17:29:53 +00:00
|
|
|
|
<Dialog
|
|
|
|
|
|
isOpen={toolbarModalData?.open || false}
|
|
|
|
|
|
onClose={() => setToolbarModalData(undefined)}
|
|
|
|
|
|
onRequestClose={() => setToolbarModalData(undefined)}
|
|
|
|
|
|
>
|
|
|
|
|
|
{toolbarModalData?.content}
|
|
|
|
|
|
</Dialog>
|
2026-02-24 20:44:16 +00:00
|
|
|
|
<Dialog
|
|
|
|
|
|
id="confirmDelete"
|
|
|
|
|
|
isOpen={!!deleteRowId}
|
|
|
|
|
|
onClose={() => setDeleteRowId(undefined)}
|
|
|
|
|
|
onRequestClose={() => setDeleteRowId(undefined)}
|
|
|
|
|
|
>
|
2026-08-14 14:03:34 +00:00
|
|
|
|
<h5 className="mb-4">{translate('::App.Platform.Delete')}</h5>
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
2026-08-14 14:03:34 +00:00
|
|
|
|
<p>{translate('::App.Platform.DeleteConfirmation')}</p>
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
|
|
|
|
|
<div className="text-right mt-6">
|
|
|
|
|
|
<Button
|
|
|
|
|
|
className="ltr:mr-2 rtl:ml-2"
|
|
|
|
|
|
variant="plain"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
setDeleteRowId(undefined)
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
2026-08-14 14:03:34 +00:00
|
|
|
|
{translate('::App.Platform.Cancel')}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
</Button>
|
2026-06-26 08:59:13 +00:00
|
|
|
|
<Button variant="solid" onClick={handleDelete}>
|
2026-08-14 14:03:34 +00:00
|
|
|
|
{translate('::App.Platform.Delete')}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
</Button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Dialog>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default FormButtons
|