2026-02-04 17:36:18 +00:00
|
|
|
import React, { Suspense, startTransition, useCallback, useEffect, useMemo, useState } from 'react'
|
2025-11-28 13:31:53 +00:00
|
|
|
import { useParams, useSearchParams } from 'react-router-dom'
|
2025-09-20 21:39:53 +00:00
|
|
|
import classNames from 'classnames'
|
2026-02-04 17:36:18 +00:00
|
|
|
|
|
|
|
|
import Container from '@/components/shared/Container'
|
|
|
|
|
import { Badge, Button } from '@/components/ui'
|
2025-09-20 21:39:53 +00:00
|
|
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
2026-02-04 17:36:18 +00:00
|
|
|
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
|
|
|
|
|
|
|
|
|
|
import { useStoreActions, useStoreState } from '@/store/store'
|
2025-09-20 21:39:53 +00:00
|
|
|
import { GridDto } from '@/proxy/form/models'
|
2025-09-22 14:08:42 +00:00
|
|
|
import { getList } from '@/services/form.service'
|
2025-09-27 11:51:05 +00:00
|
|
|
import { ListViewLayoutType } from '../admin/listForm/edit/types'
|
2025-05-06 06:45:49 +00:00
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
import {
|
|
|
|
|
FaChartArea,
|
|
|
|
|
FaList,
|
|
|
|
|
FaSitemap,
|
|
|
|
|
FaTable,
|
|
|
|
|
FaCalendarAlt,
|
|
|
|
|
FaProjectDiagram,
|
|
|
|
|
} from 'react-icons/fa'
|
|
|
|
|
|
|
|
|
|
/* =======================
|
|
|
|
|
🔥 LAZY VIEW IMPORTS
|
|
|
|
|
======================= */
|
|
|
|
|
const Grid = React.lazy(() => import('./Grid'))
|
|
|
|
|
const Pivot = React.lazy(() => import('./Pivot'))
|
|
|
|
|
const Tree = React.lazy(() => import('./Tree'))
|
|
|
|
|
const Chart = React.lazy(() => import('./Chart'))
|
|
|
|
|
const GanttView = React.lazy(() => import('./GanttView'))
|
|
|
|
|
const SchedulerView = React.lazy(() => import('./SchedulerView'))
|
|
|
|
|
|
|
|
|
|
const List: React.FC = () => {
|
|
|
|
|
const { listFormCode = '' } = useParams()
|
2025-05-06 06:45:49 +00:00
|
|
|
const [searchParams] = useSearchParams()
|
2025-09-23 12:48:54 +00:00
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
const { translate } = useLocalization()
|
|
|
|
|
const mode = useStoreState((state) => state.theme.mode)
|
2025-09-23 10:30:57 +00:00
|
|
|
const MenuIcon = useCurrentMenuIcon('w-5 h-5')
|
2025-05-06 06:45:49 +00:00
|
|
|
|
2025-10-02 10:08:48 +00:00
|
|
|
const { states } = useStoreState((state) => state.admin.lists)
|
|
|
|
|
const { setStates } = useStoreActions((a) => a.admin.lists)
|
2025-09-23 12:48:54 +00:00
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
const [gridDto, setGridDto] = useState<GridDto | null>(null)
|
|
|
|
|
const [viewMode, setViewMode] = useState<ListViewLayoutType | undefined>()
|
|
|
|
|
|
|
|
|
|
/* =======================
|
|
|
|
|
🔹 GRID DTO FETCH
|
|
|
|
|
======================= */
|
|
|
|
|
const refreshGridDto = useCallback(async () => {
|
2025-09-27 20:25:21 +00:00
|
|
|
if (!listFormCode) return
|
|
|
|
|
try {
|
2025-09-23 14:05:42 +00:00
|
|
|
const response = await getList({ listFormCode })
|
|
|
|
|
setGridDto(response.data)
|
2026-02-04 17:36:18 +00:00
|
|
|
} catch (err) {
|
|
|
|
|
console.error('GridDto load error:', err)
|
2025-09-22 14:08:42 +00:00
|
|
|
}
|
2026-02-04 17:36:18 +00:00
|
|
|
}, [listFormCode])
|
2025-09-22 14:08:42 +00:00
|
|
|
|
2025-09-27 20:25:21 +00:00
|
|
|
useEffect(() => {
|
2025-11-07 23:00:51 +00:00
|
|
|
refreshGridDto()
|
2026-02-04 17:36:18 +00:00
|
|
|
}, [refreshGridDto])
|
2025-09-22 14:08:42 +00:00
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
/* =======================
|
|
|
|
|
🔹 INITIAL VIEW MODE
|
|
|
|
|
======================= */
|
2025-11-07 23:00:51 +00:00
|
|
|
useEffect(() => {
|
2026-02-04 17:36:18 +00:00
|
|
|
if (!gridDto) return
|
2025-11-07 23:00:51 +00:00
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
const savedLayout = states.find((s) => s.listFormCode === listFormCode)?.layout
|
2025-11-07 23:00:51 +00:00
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
const defaultLayout = gridDto.gridOptions?.layoutDto?.defaultLayout
|
2025-11-07 23:00:51 +00:00
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
setViewMode(savedLayout ?? defaultLayout)
|
|
|
|
|
}, [gridDto, states, listFormCode])
|
2025-09-20 21:39:53 +00:00
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
/* =======================
|
|
|
|
|
🔹 VIEW SWITCH HANDLER
|
|
|
|
|
======================= */
|
|
|
|
|
const setLayout = useCallback(
|
|
|
|
|
(layout: ListViewLayoutType) => {
|
|
|
|
|
startTransition(() => {
|
|
|
|
|
setViewMode(layout)
|
|
|
|
|
})
|
|
|
|
|
setStates({ listFormCode, layout })
|
|
|
|
|
},
|
|
|
|
|
[listFormCode, setStates],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/* =======================
|
|
|
|
|
🔹 PRELOAD MAP (HOVER)
|
|
|
|
|
======================= */
|
|
|
|
|
const preload = useMemo(
|
|
|
|
|
() => ({
|
|
|
|
|
grid: () => import('./Grid'),
|
|
|
|
|
pivot: () => import('./Pivot'),
|
|
|
|
|
tree: () => import('./Tree'),
|
|
|
|
|
chart: () => import('./Chart'),
|
|
|
|
|
gantt: () => import('./GanttView'),
|
|
|
|
|
scheduler: () => import('./SchedulerView'),
|
|
|
|
|
}),
|
|
|
|
|
[],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if (!listFormCode || !gridDto || !viewMode) {
|
2025-09-23 19:52:08 +00:00
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-20 21:39:53 +00:00
|
|
|
return (
|
2025-05-06 06:45:49 +00:00
|
|
|
<Container>
|
2026-02-04 17:36:18 +00:00
|
|
|
{/* =======================
|
|
|
|
|
HEADER
|
|
|
|
|
======================= */}
|
2025-09-23 14:05:42 +00:00
|
|
|
<div
|
2026-02-04 17:36:18 +00:00
|
|
|
className={classNames(
|
|
|
|
|
'flex items-center gap-2 pb-1 border-b',
|
|
|
|
|
mode === 'light' ? 'border-gray-200' : 'border-neutral-700',
|
|
|
|
|
)}
|
2025-09-23 14:05:42 +00:00
|
|
|
>
|
2026-02-04 17:36:18 +00:00
|
|
|
{MenuIcon}
|
|
|
|
|
<h4 className="text-sm font-medium">{translate('::' + gridDto.gridOptions.title)}</h4>
|
|
|
|
|
<Badge content={viewMode} />
|
2025-09-20 21:39:53 +00:00
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
{/* =======================
|
|
|
|
|
VIEW BUTTONS
|
|
|
|
|
======================= */}
|
2026-02-04 18:25:35 +00:00
|
|
|
<div className="flex gap-1 ml-auto">
|
2025-12-02 18:15:09 +00:00
|
|
|
{gridDto?.gridOptions?.layoutDto.scheduler &&
|
|
|
|
|
gridDto?.gridOptions?.schedulerOptionDto?.textExpr &&
|
|
|
|
|
gridDto?.gridOptions?.schedulerOptionDto?.startDateExpr && (
|
|
|
|
|
<Button
|
|
|
|
|
size="xs"
|
|
|
|
|
variant={viewMode === 'scheduler' ? 'solid' : 'default'}
|
2026-02-04 17:36:18 +00:00
|
|
|
onClick={() => setLayout('scheduler')}
|
|
|
|
|
onMouseEnter={() => preload.scheduler()}
|
2025-12-02 18:15:09 +00:00
|
|
|
>
|
2026-02-04 17:36:18 +00:00
|
|
|
<FaCalendarAlt />
|
2025-12-02 18:15:09 +00:00
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
|
2025-12-01 14:45:23 +00:00
|
|
|
{gridDto?.gridOptions?.layoutDto.gantt &&
|
2025-12-02 18:15:09 +00:00
|
|
|
gridDto?.gridOptions?.ganttOptionDto?.parentIdExpr &&
|
|
|
|
|
gridDto?.gridOptions?.ganttOptionDto?.titleExpr && (
|
2025-12-01 14:45:23 +00:00
|
|
|
<Button
|
|
|
|
|
size="xs"
|
|
|
|
|
variant={viewMode === 'gantt' ? 'solid' : 'default'}
|
2026-02-04 17:36:18 +00:00
|
|
|
onClick={() => setLayout('gantt')}
|
|
|
|
|
onMouseEnter={() => preload.gantt()}
|
2025-12-01 14:45:23 +00:00
|
|
|
>
|
2026-02-04 17:36:18 +00:00
|
|
|
<FaProjectDiagram />
|
2025-12-01 14:45:23 +00:00
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
|
2025-11-07 23:00:51 +00:00
|
|
|
{gridDto?.gridOptions?.layoutDto.tree &&
|
|
|
|
|
gridDto?.gridOptions?.treeOptionDto?.parentIdExpr && (
|
|
|
|
|
<Button
|
|
|
|
|
size="xs"
|
|
|
|
|
variant={viewMode === 'tree' ? 'solid' : 'default'}
|
2026-02-04 17:36:18 +00:00
|
|
|
onClick={() => setLayout('tree')}
|
|
|
|
|
onMouseEnter={() => preload.tree()}
|
2025-11-07 23:00:51 +00:00
|
|
|
>
|
2026-02-04 17:36:18 +00:00
|
|
|
<FaSitemap />
|
2025-11-07 23:00:51 +00:00
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
<Button
|
|
|
|
|
size="xs"
|
|
|
|
|
variant={viewMode === 'grid' ? 'solid' : 'default'}
|
|
|
|
|
onClick={() => setLayout('grid')}
|
|
|
|
|
onMouseEnter={() => preload.grid()}
|
|
|
|
|
>
|
|
|
|
|
<FaList />
|
|
|
|
|
</Button>
|
2025-09-22 14:08:42 +00:00
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
{gridDto.gridOptions.layoutDto.pivot && (
|
2025-09-23 14:05:42 +00:00
|
|
|
<Button
|
|
|
|
|
size="xs"
|
|
|
|
|
variant={viewMode === 'pivot' ? 'solid' : 'default'}
|
2026-02-04 17:36:18 +00:00
|
|
|
onClick={() => setLayout('pivot')}
|
|
|
|
|
onMouseEnter={() => preload.pivot()}
|
2025-09-23 14:05:42 +00:00
|
|
|
>
|
2026-02-04 17:36:18 +00:00
|
|
|
<FaTable />
|
2025-09-23 14:05:42 +00:00
|
|
|
</Button>
|
2025-09-22 14:08:42 +00:00
|
|
|
)}
|
2025-09-27 11:51:05 +00:00
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
{gridDto.gridOptions.layoutDto.chart && (
|
2025-09-27 11:51:05 +00:00
|
|
|
<Button
|
|
|
|
|
size="xs"
|
|
|
|
|
variant={viewMode === 'chart' ? 'solid' : 'default'}
|
2026-02-04 17:36:18 +00:00
|
|
|
onClick={() => setLayout('chart')}
|
|
|
|
|
onMouseEnter={() => preload.chart()}
|
2025-09-27 11:51:05 +00:00
|
|
|
>
|
2026-02-04 17:36:18 +00:00
|
|
|
<FaChartArea />
|
2025-09-27 11:51:05 +00:00
|
|
|
</Button>
|
|
|
|
|
)}
|
2025-09-23 14:05:42 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-02-04 17:36:18 +00:00
|
|
|
{/* =======================
|
|
|
|
|
VIEW RENDER
|
|
|
|
|
======================= */}
|
|
|
|
|
<Suspense fallback={<div className="p-4 text-sm">Yükleniyor...</div>}>
|
|
|
|
|
{viewMode === 'grid' && (
|
|
|
|
|
<Grid
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
searchParams={searchParams}
|
|
|
|
|
isSubForm={false}
|
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{viewMode === 'pivot' && (
|
|
|
|
|
<Pivot
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
searchParams={searchParams}
|
|
|
|
|
isSubForm={false}
|
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
refreshGridDto={refreshGridDto}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{viewMode === 'tree' && (
|
|
|
|
|
<Tree
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
searchParams={searchParams}
|
|
|
|
|
isSubForm={false}
|
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{viewMode === 'scheduler' && (
|
|
|
|
|
<SchedulerView
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
searchParams={searchParams}
|
|
|
|
|
isSubForm={false}
|
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{viewMode === 'gantt' && (
|
|
|
|
|
<GanttView
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
searchParams={searchParams}
|
|
|
|
|
isSubForm={false}
|
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{viewMode === 'chart' && (
|
|
|
|
|
<Chart
|
|
|
|
|
id={gridDto?.gridOptions.id!}
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
filter={searchParams.toString()}
|
|
|
|
|
isSubForm={true}
|
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
refreshGridDto={refreshGridDto}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Suspense>
|
2025-05-06 06:45:49 +00:00
|
|
|
</Container>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default List
|