erp-platform/ui/src/views/list/List.tsx

266 lines
7.8 KiB
TypeScript
Raw Normal View History

import React, { Suspense, startTransition, useCallback, useEffect, useMemo, useState } from 'react'
import { useParams, useSearchParams } from 'react-router-dom'
2025-09-20 21:39:53 +00:00
import classNames from 'classnames'
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'
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
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()
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
const { states } = useStoreState((state) => state.admin.lists)
const { setStates } = useStoreActions((a) => a.admin.lists)
const [gridDto, setGridDto] = useState<GridDto | null>(null)
const [viewMode, setViewMode] = useState<ListViewLayoutType | undefined>()
/* =======================
🔹 GRID DTO FETCH
======================= */
const refreshGridDto = useCallback(async () => {
if (!listFormCode) return
try {
const response = await getList({ listFormCode })
setGridDto(response.data)
} catch (err) {
console.error('GridDto load error:', err)
2025-09-22 14:08:42 +00:00
}
}, [listFormCode])
2025-09-22 14:08:42 +00:00
useEffect(() => {
refreshGridDto()
}, [refreshGridDto])
2025-09-22 14:08:42 +00:00
/* =======================
🔹 INITIAL VIEW MODE
======================= */
useEffect(() => {
if (!gridDto) return
const savedLayout = states.find((s) => s.listFormCode === listFormCode)?.layout
const defaultLayout = gridDto.gridOptions?.layoutDto?.defaultLayout
setViewMode(savedLayout ?? defaultLayout)
}, [gridDto, states, listFormCode])
2025-09-20 21:39:53 +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>
{/* =======================
HEADER
======================= */}
<div
className={classNames(
'flex items-center gap-2 pb-1 border-b',
mode === 'light' ? 'border-gray-200' : 'border-neutral-700',
)}
>
{MenuIcon}
<h4 className="text-sm font-medium">{translate('::' + gridDto.gridOptions.title)}</h4>
<Badge content={viewMode} />
2025-09-20 21:39:53 +00:00
{/* =======================
VIEW BUTTONS
======================= */}
<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'}
onClick={() => setLayout('scheduler')}
onMouseEnter={() => preload.scheduler()}
2025-12-02 18:15:09 +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'}
onClick={() => setLayout('gantt')}
onMouseEnter={() => preload.gantt()}
2025-12-01 14:45:23 +00:00
>
<FaProjectDiagram />
2025-12-01 14:45:23 +00:00
</Button>
)}
{gridDto?.gridOptions?.layoutDto.tree &&
gridDto?.gridOptions?.treeOptionDto?.parentIdExpr && (
<Button
size="xs"
variant={viewMode === 'tree' ? 'solid' : 'default'}
onClick={() => setLayout('tree')}
onMouseEnter={() => preload.tree()}
>
<FaSitemap />
</Button>
)}
<Button
size="xs"
variant={viewMode === 'grid' ? 'solid' : 'default'}
onClick={() => setLayout('grid')}
onMouseEnter={() => preload.grid()}
>
<FaList />
</Button>
2025-09-22 14:08:42 +00:00
{gridDto.gridOptions.layoutDto.pivot && (
<Button
size="xs"
variant={viewMode === 'pivot' ? 'solid' : 'default'}
onClick={() => setLayout('pivot')}
onMouseEnter={() => preload.pivot()}
>
<FaTable />
</Button>
2025-09-22 14:08:42 +00:00
)}
2025-09-27 11:51:05 +00:00
{gridDto.gridOptions.layoutDto.chart && (
2025-09-27 11:51:05 +00:00
<Button
size="xs"
variant={viewMode === 'chart' ? 'solid' : 'default'}
onClick={() => setLayout('chart')}
onMouseEnter={() => preload.chart()}
2025-09-27 11:51:05 +00:00
>
<FaChartArea />
2025-09-27 11:51:05 +00:00
</Button>
)}
</div>
</div>
{/* =======================
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