Grid ve Card Görünümü
This commit is contained in:
parent
a01422ca60
commit
3f69cc54e9
8 changed files with 363 additions and 144 deletions
|
|
@ -18,7 +18,7 @@ export declare namespace TypeAttributes {
|
||||||
type Shape = 'round' | 'circle' | 'none'
|
type Shape = 'round' | 'circle' | 'none'
|
||||||
type Status = 'success' | 'warning' | 'danger' | 'info'
|
type Status = 'success' | 'warning' | 'danger' | 'info'
|
||||||
type FormLayout = 'horizontal' | 'vertical' | 'inline'
|
type FormLayout = 'horizontal' | 'vertical' | 'inline'
|
||||||
type ControlSize = 'lg' | 'md' | 'sm'
|
type ControlSize = 'lg' | 'md' | 'sm' | 'xs'
|
||||||
type MenuVariant = 'light' | 'dark' | 'themed' | 'transparent'
|
type MenuVariant = 'light' | 'dark' | 'themed' | 'transparent'
|
||||||
type Direction = 'ltr' | 'rtl'
|
type Direction = 'ltr' | 'rtl'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,132 +8,130 @@ import { useConfig } from '../ConfigProvider'
|
||||||
import type { CommonProps } from '../@types/common'
|
import type { CommonProps } from '../@types/common'
|
||||||
|
|
||||||
export interface PaginationProps extends CommonProps {
|
export interface PaginationProps extends CommonProps {
|
||||||
currentPage?: number
|
currentPage?: number
|
||||||
displayTotal?: boolean
|
displayTotal?: boolean
|
||||||
onChange?: (pageNumber: number) => void
|
onChange?: (pageNumber: number) => void
|
||||||
pageSize?: number
|
pageSize?: number
|
||||||
total?: number
|
total?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const Pagination = (props: PaginationProps) => {
|
const Pagination = (props: PaginationProps) => {
|
||||||
const {
|
const {
|
||||||
className,
|
className,
|
||||||
currentPage = 1,
|
currentPage = 1,
|
||||||
displayTotal = false,
|
displayTotal = false,
|
||||||
onChange,
|
onChange,
|
||||||
pageSize = 1,
|
pageSize = 1,
|
||||||
total = 5,
|
total = 5,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const [paginationTotal, setPaginationTotal] = useState(total)
|
const [paginationTotal, setPaginationTotal] = useState(total)
|
||||||
const [internalPageSize, setInternalPageSize] = useState(pageSize)
|
const [internalPageSize, setInternalPageSize] = useState(pageSize)
|
||||||
|
|
||||||
const { themeColor, primaryColorLevel } = useConfig()
|
const { themeColor, primaryColorLevel } = useConfig()
|
||||||
|
|
||||||
const getInternalPageCount = useMemo(() => {
|
const getInternalPageCount = useMemo(() => {
|
||||||
if (typeof paginationTotal === 'number') {
|
if (typeof paginationTotal === 'number') {
|
||||||
return Math.ceil(paginationTotal / internalPageSize)
|
return Math.ceil(paginationTotal / internalPageSize)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}, [paginationTotal, internalPageSize])
|
||||||
|
|
||||||
|
const getValidCurrentPage = useCallback(
|
||||||
|
(count: number | string) => {
|
||||||
|
const value = parseInt(count as string, 10)
|
||||||
|
const internalPageCount = getInternalPageCount
|
||||||
|
let resetValue
|
||||||
|
if (!internalPageCount) {
|
||||||
|
if (isNaN(value) || value < 1) {
|
||||||
|
resetValue = 1
|
||||||
}
|
}
|
||||||
return null
|
} else {
|
||||||
}, [paginationTotal, internalPageSize])
|
if (value < 1) {
|
||||||
|
resetValue = 1
|
||||||
const getValidCurrentPage = useCallback(
|
|
||||||
(count: number | string) => {
|
|
||||||
const value = parseInt(count as string, 10)
|
|
||||||
const internalPageCount = getInternalPageCount
|
|
||||||
let resetValue
|
|
||||||
if (!internalPageCount) {
|
|
||||||
if (isNaN(value) || value < 1) {
|
|
||||||
resetValue = 1
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (value < 1) {
|
|
||||||
resetValue = 1
|
|
||||||
}
|
|
||||||
if (value > internalPageCount) {
|
|
||||||
resetValue = internalPageCount
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(resetValue === undefined && isNaN(value)) ||
|
|
||||||
resetValue === 0
|
|
||||||
) {
|
|
||||||
resetValue = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return resetValue === undefined ? value : resetValue
|
|
||||||
},
|
|
||||||
[getInternalPageCount]
|
|
||||||
)
|
|
||||||
|
|
||||||
const [internalCurrentPage, setInternalCurrentPage] = useState(
|
|
||||||
currentPage ? getValidCurrentPage(currentPage) : 1
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (total !== paginationTotal) {
|
|
||||||
setPaginationTotal(total)
|
|
||||||
}
|
}
|
||||||
|
if (value > internalPageCount) {
|
||||||
if (pageSize !== internalPageSize) {
|
resetValue = internalPageCount
|
||||||
setInternalPageSize(pageSize)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (currentPage !== internalCurrentPage) {
|
if ((resetValue === undefined && isNaN(value)) || resetValue === 0) {
|
||||||
setInternalCurrentPage(currentPage)
|
resetValue = 1
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [total, pageSize, currentPage])
|
|
||||||
|
|
||||||
const onPaginationChange = (val: number) => {
|
return resetValue === undefined ? value : resetValue
|
||||||
setInternalCurrentPage(getValidCurrentPage(val))
|
},
|
||||||
onChange?.(getValidCurrentPage(val))
|
[getInternalPageCount],
|
||||||
|
)
|
||||||
|
|
||||||
|
const [internalCurrentPage, setInternalCurrentPage] = useState(
|
||||||
|
currentPage ? getValidCurrentPage(currentPage) : 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (total !== paginationTotal) {
|
||||||
|
setPaginationTotal(total)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPrev = useCallback(() => {
|
if (pageSize !== internalPageSize) {
|
||||||
const newPage = internalCurrentPage - 1
|
setInternalPageSize(pageSize)
|
||||||
setInternalCurrentPage(getValidCurrentPage(newPage))
|
|
||||||
onChange?.(getValidCurrentPage(newPage))
|
|
||||||
}, [onChange, internalCurrentPage, getValidCurrentPage])
|
|
||||||
|
|
||||||
const onNext = useCallback(() => {
|
|
||||||
const newPage = internalCurrentPage + 1
|
|
||||||
setInternalCurrentPage(getValidCurrentPage(newPage))
|
|
||||||
onChange?.(getValidCurrentPage(newPage))
|
|
||||||
}, [onChange, internalCurrentPage, getValidCurrentPage])
|
|
||||||
|
|
||||||
const pagerClass = {
|
|
||||||
default: 'pagination-pager',
|
|
||||||
inactive: 'pagination-pager-inactive',
|
|
||||||
active: `text-${themeColor}-${primaryColorLevel} bg-${themeColor}-50 hover:bg-${themeColor}-50 dark:bg-${themeColor}-${primaryColorLevel} dark:text-gray-100`,
|
|
||||||
disabled: 'pagination-pager-disabled',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const paginationClass = classNames('pagination', className)
|
if (currentPage !== internalCurrentPage) {
|
||||||
|
setInternalCurrentPage(currentPage)
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [total, pageSize, currentPage])
|
||||||
|
|
||||||
return (
|
const onPaginationChange = (val: number) => {
|
||||||
<div className={paginationClass}>
|
setInternalCurrentPage(getValidCurrentPage(val))
|
||||||
{displayTotal && <Total total={total} />}
|
onChange?.(getValidCurrentPage(val))
|
||||||
<Prev
|
}
|
||||||
currentPage={internalCurrentPage}
|
|
||||||
pagerClass={pagerClass}
|
const onPrev = useCallback(() => {
|
||||||
onPrev={onPrev}
|
const newPage = internalCurrentPage - 1
|
||||||
/>
|
setInternalCurrentPage(getValidCurrentPage(newPage))
|
||||||
<Pager
|
onChange?.(getValidCurrentPage(newPage))
|
||||||
pageCount={getInternalPageCount as number}
|
}, [onChange, internalCurrentPage, getValidCurrentPage])
|
||||||
currentPage={internalCurrentPage}
|
|
||||||
pagerClass={pagerClass}
|
const onNext = useCallback(() => {
|
||||||
onChange={onPaginationChange}
|
const newPage = internalCurrentPage + 1
|
||||||
/>
|
setInternalCurrentPage(getValidCurrentPage(newPage))
|
||||||
<Next
|
onChange?.(getValidCurrentPage(newPage))
|
||||||
currentPage={internalCurrentPage}
|
}, [onChange, internalCurrentPage, getValidCurrentPage])
|
||||||
pageCount={getInternalPageCount as number}
|
|
||||||
pagerClass={pagerClass}
|
const pagerClass = {
|
||||||
onNext={onNext}
|
default: 'pagination-pager px-2 py-1 text-xs rounded-md', // 🔽 küçük padding + küçük yazı
|
||||||
/>
|
inactive: 'pagination-pager-inactive text-gray-500',
|
||||||
</div>
|
active: `text-${themeColor}-${primaryColorLevel} bg-${themeColor}-50
|
||||||
)
|
hover:bg-${themeColor}-100
|
||||||
|
dark:bg-${themeColor}-${primaryColorLevel} dark:text-gray-100`,
|
||||||
|
disabled: 'pagination-pager-disabled opacity-50',
|
||||||
|
}
|
||||||
|
|
||||||
|
const paginationClass = classNames(
|
||||||
|
'pagination flex items-center justify-center text-xs', // 🔽 daha küçük yazı + boşluk azaldı
|
||||||
|
className,
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={paginationClass}>
|
||||||
|
{displayTotal && <Total total={total} />}
|
||||||
|
<Prev currentPage={internalCurrentPage} pagerClass={pagerClass} onPrev={onPrev} />
|
||||||
|
<Pager
|
||||||
|
pageCount={getInternalPageCount as number}
|
||||||
|
currentPage={internalCurrentPage}
|
||||||
|
pagerClass={pagerClass}
|
||||||
|
onChange={onPaginationChange}
|
||||||
|
/>
|
||||||
|
<Next
|
||||||
|
currentPage={internalCurrentPage}
|
||||||
|
pageCount={getInternalPageCount as number}
|
||||||
|
pagerClass={pagerClass}
|
||||||
|
onNext={onNext}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Pagination.displayName = 'Pagination'
|
Pagination.displayName = 'Pagination'
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ const FormButtons = (props: {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-row items-center gap-2">
|
<div className="flex flex-row items-center gap-1">
|
||||||
{toolbarData
|
{toolbarData
|
||||||
?.filter(
|
?.filter(
|
||||||
(item) =>
|
(item) =>
|
||||||
|
|
@ -168,6 +168,21 @@ const FormButtons = (props: {
|
||||||
{!!commandColumnData?.buttons?.filter((item) => typeof item !== 'string').length && (
|
{!!commandColumnData?.buttons?.filter((item) => typeof item !== 'string').length && (
|
||||||
<Badge innerClass="bg-blue-500" />
|
<Badge innerClass="bg-blue-500" />
|
||||||
)}
|
)}
|
||||||
|
<Button
|
||||||
|
variant="solid"
|
||||||
|
size="xs"
|
||||||
|
color="gray-500"
|
||||||
|
title={translate('::Cancel')}
|
||||||
|
onClick={() => {
|
||||||
|
if (onActionView && id) {
|
||||||
|
onActionView()
|
||||||
|
} else {
|
||||||
|
navigate(-1)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FaBackward />
|
||||||
|
</Button>
|
||||||
{mode != 'new' && (
|
{mode != 'new' && (
|
||||||
<Button
|
<Button
|
||||||
variant="solid"
|
variant="solid"
|
||||||
|
|
@ -241,23 +256,6 @@ const FormButtons = (props: {
|
||||||
<FaFileAlt />
|
<FaFileAlt />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{mode === 'new' && (
|
|
||||||
<Button
|
|
||||||
variant="solid"
|
|
||||||
size="xs"
|
|
||||||
color="gray-500"
|
|
||||||
title={translate('::Cancel')}
|
|
||||||
onClick={() => {
|
|
||||||
if (onActionView && id) {
|
|
||||||
onActionView()
|
|
||||||
} else {
|
|
||||||
navigate(-1)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FaBackward />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{(mode == 'edit' || mode == 'new') && (
|
{(mode == 'edit' || mode == 'new') && (
|
||||||
<Button
|
<Button
|
||||||
variant="solid"
|
variant="solid"
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ const FormEdit = (
|
||||||
defaultTitle="Sözsoft Kurs Platform"
|
defaultTitle="Sözsoft Kurs Platform"
|
||||||
></Helmet>
|
></Helmet>
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<h3>{translate('::' + gridDto?.gridOptions.title)}</h3>
|
<h3>{translate('::' + gridDto?.gridOptions.title)}</h3>
|
||||||
{permissionResults && (
|
{permissionResults && (
|
||||||
<FormButtons
|
<FormButtons
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ const FormView = (
|
||||||
defaultTitle="Sözsoft Kurs Platform"
|
defaultTitle="Sözsoft Kurs Platform"
|
||||||
></Helmet>
|
></Helmet>
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<h3>{translate('::' + gridDto?.gridOptions.title)}</h3>
|
<h3>{translate('::' + gridDto?.gridOptions.title)}</h3>
|
||||||
{permissionResults && (
|
{permissionResults && (
|
||||||
<FormButtons
|
<FormButtons
|
||||||
|
|
|
||||||
167
ui/src/views/list/CardView.tsx
Normal file
167
ui/src/views/list/CardView.tsx
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
import React, { useCallback, useEffect, useState } from 'react'
|
||||||
|
import { GridDto } from '@/proxy/form/models'
|
||||||
|
import { captionize } from 'devextreme/core/utils/inflector'
|
||||||
|
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { Pagination, Select } from '@/components/ui'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import { useStoreState } from '@/store/store'
|
||||||
|
import { getList } from '@/services/form.service'
|
||||||
|
import { FaAngleRight } from 'react-icons/fa'
|
||||||
|
|
||||||
|
interface MultiFormViewProps {
|
||||||
|
listFormCode: string
|
||||||
|
searchParams?: URLSearchParams
|
||||||
|
}
|
||||||
|
|
||||||
|
const CardView = ({ listFormCode, searchParams }: MultiFormViewProps) => {
|
||||||
|
const { createSelectDataSource } = useListFormCustomDataSource({})
|
||||||
|
const [gridDto, setGridDto] = useState<GridDto>()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const [data, setData] = useState<any[]>([])
|
||||||
|
const [totalCount, setTotalCount] = useState(0)
|
||||||
|
const [currentPage, setCurrentPage] = useState(1)
|
||||||
|
const [pageSize, setPageSize] = useState(10)
|
||||||
|
const [pageSizeOptions, setPageSizeOptions] = useState<Option[]>([])
|
||||||
|
const mode = useStoreState((state) => state.theme.mode)
|
||||||
|
|
||||||
|
type Option = {
|
||||||
|
value: number
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPageSizeSelect = ({ value }: Option) => {
|
||||||
|
setPageSize(value)
|
||||||
|
setCurrentPage(1) // Sayfa boyutu değiştiğinde ilk sayfaya dön
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPageChange = (page: number) => {
|
||||||
|
setCurrentPage(page)
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadData = useCallback(() => {
|
||||||
|
if (!gridDto) return
|
||||||
|
|
||||||
|
const store = createSelectDataSource(gridDto.gridOptions, listFormCode, searchParams)
|
||||||
|
|
||||||
|
const loadOptions = {
|
||||||
|
skip: (currentPage - 1) * pageSize,
|
||||||
|
take: pageSize,
|
||||||
|
requireTotalCount: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
store.load(loadOptions).then((res: any) => {
|
||||||
|
setData(res.data)
|
||||||
|
setTotalCount(res.totalCount || 0)
|
||||||
|
})
|
||||||
|
}, [gridDto, listFormCode, searchParams, currentPage, pageSize])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getList({ listFormCode }).then((res: any) => setGridDto(res.data))
|
||||||
|
}, [listFormCode])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!gridDto) return
|
||||||
|
|
||||||
|
const pagerOptions = gridDto.gridOptions.pagerOptionDto
|
||||||
|
// const initialPageSize = gridDto.gridOptions.pageSize || 10
|
||||||
|
const allowedSizes = pagerOptions?.allowedPageSizes
|
||||||
|
?.split(',')
|
||||||
|
.map((s) => Number(s.trim()))
|
||||||
|
.filter((n) => !isNaN(n) && n > 0) || [20, 50, 100]
|
||||||
|
|
||||||
|
// setPageSize(initialPageSize)
|
||||||
|
setPageSizeOptions(allowedSizes.map((size) => ({ value: size, label: `${size} page` })))
|
||||||
|
}, [gridDto, listFormCode, searchParams])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadData()
|
||||||
|
}, [loadData])
|
||||||
|
|
||||||
|
if (!gridDto) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4">
|
||||||
|
{data.map((row, idx) => {
|
||||||
|
const keyField = gridDto.gridOptions.keyFieldName
|
||||||
|
const rowId = row[keyField!]
|
||||||
|
|
||||||
|
const handleCardClick = () => {
|
||||||
|
if (rowId) {
|
||||||
|
navigate(`/admin/form/${listFormCode}/${rowId}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={rowId || idx}
|
||||||
|
className="bg-white dark:bg-neutral-800 hover:shadow-xl hover:border-blue-400 border dark:border-neutral-700 transition-all duration-300 cursor-pointer flex flex-col group"
|
||||||
|
onClick={handleCardClick}
|
||||||
|
>
|
||||||
|
<div className="p-4 flex-grow">
|
||||||
|
<div className="grid grid-cols-1 gap-y-3">
|
||||||
|
{gridDto.columnFormats
|
||||||
|
.filter((col) => col.visible && col.listOrderNo > 0)
|
||||||
|
.sort((a, b) => a.listOrderNo - b.listOrderNo)
|
||||||
|
.slice(0, 10) // İlk 10 görünür alanı gösterelim
|
||||||
|
.map((col, colIdx) => (
|
||||||
|
<div key={col.fieldName} className="truncate text-sm">
|
||||||
|
<p className="text-xs text-slate-500 dark:text-slate-400 mb-0.5">
|
||||||
|
{captionize(col.captionName || col.fieldName)}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
className={classNames(
|
||||||
|
'truncate',
|
||||||
|
colIdx === 0
|
||||||
|
? 'font-semibold text-base text-slate-800 dark:text-slate-100'
|
||||||
|
: 'text-slate-700 dark:text-slate-300',
|
||||||
|
)}
|
||||||
|
title={row[col.fieldName!]}
|
||||||
|
>
|
||||||
|
{row[col.fieldName!]}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-gray-50 dark:bg-neutral-700/50 p-2 border-t border-gray-100 dark:border-neutral-700 flex items-center justify-end text-xs font-semibold text-blue-600 dark:text-blue-400 opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||||
|
Görüntüle
|
||||||
|
<FaAngleRight className="ml-1 w-3 h-3" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{gridDto.gridOptions.pagerOptionDto?.visible && totalCount > pageSize && (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'flex items-center justify-between border-t-2 border-solid gap-4 p-2',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="text-xs text-gray-600 dark:text-gray-300">
|
||||||
|
Toplam {totalCount} kayıt
|
||||||
|
</span>
|
||||||
|
<Select
|
||||||
|
size='xs'
|
||||||
|
menuPlacement='top'
|
||||||
|
value={pageSizeOptions.find((o) => o.value === pageSize)}
|
||||||
|
options={pageSizeOptions}
|
||||||
|
onChange={(selected) => onPageSizeSelect(selected as Option)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Pagination
|
||||||
|
currentPage={currentPage}
|
||||||
|
total={totalCount}
|
||||||
|
pageSize={pageSize}
|
||||||
|
onChange={onPageChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CardView
|
||||||
|
|
@ -75,6 +75,7 @@ interface GridProps {
|
||||||
isSubForm?: boolean
|
isSubForm?: boolean
|
||||||
level?: number
|
level?: number
|
||||||
refreshData?: () => Promise<void>
|
refreshData?: () => Promise<void>
|
||||||
|
onGridDtoLoad?: (gridDto: GridDto) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const statedGridPanelColor = 'rgba(50, 200, 200, 0.5)' // kullanici tanimli gridState ile islem gormus gridin paneline ait renk
|
const statedGridPanelColor = 'rgba(50, 200, 200, 0.5)' // kullanici tanimli gridState ile islem gormus gridin paneline ait renk
|
||||||
|
|
@ -446,6 +447,10 @@ const Grid = (props: GridProps) => {
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gridDto) {
|
||||||
|
props.onGridDtoLoad?.(gridDto)
|
||||||
|
}
|
||||||
}, [gridDto])
|
}, [gridDto])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,75 @@
|
||||||
import { CommonProps } from '@/@types/common'
|
|
||||||
import { Meta } from '@/@types/routes'
|
|
||||||
import Container from '@/components/shared/Container'
|
|
||||||
import { useParams, useSearchParams } from 'react-router-dom'
|
import { useParams, useSearchParams } from 'react-router-dom'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import Container from '@/components/shared/Container'
|
||||||
import Grid from './Grid'
|
import Grid from './Grid'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { FaList, FaTh } from 'react-icons/fa'
|
||||||
|
import { useStoreState } from '@/store/store'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import { GridDto } from '@/proxy/form/models'
|
||||||
|
import CardView from './CardView'
|
||||||
|
|
||||||
export interface FormProps extends CommonProps, Meta {
|
const List = () => {
|
||||||
listFormCode?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const List = (props?: FormProps) => {
|
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const _listFormCode = props?.listFormCode ?? params?.listFormCode ?? ''
|
const { translate } = useLocalization()
|
||||||
const [searchParams] = useSearchParams()
|
const [searchParams] = useSearchParams()
|
||||||
|
const listFormCode = params?.listFormCode ?? ''
|
||||||
|
const [viewMode, setViewMode] = useState<'grid' | 'card'>('grid')
|
||||||
|
const mode = useStoreState((state) => state.theme.mode)
|
||||||
|
const [gridDto, setGridDto] = useState<GridDto>()
|
||||||
|
|
||||||
return _listFormCode ? (
|
if (!listFormCode) return null
|
||||||
|
|
||||||
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Grid listFormCode={_listFormCode} searchParams={searchParams} isSubForm={false}></Grid>
|
<div
|
||||||
|
className={classNames('flex items-center border-b-2 border-solid gap-1 pb-1', {
|
||||||
|
'border-gray-100': mode === 'light',
|
||||||
|
'border-neutral-700': mode === 'dark',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<h3>{translate('::' + gridDto?.gridOptions?.title)}</h3>
|
||||||
|
|
||||||
|
{gridDto?.gridOptions?.description === gridDto?.gridOptions?.title ? (
|
||||||
|
<p className="text-gray-600 mr-auto pt-1 ml-2"></p>
|
||||||
|
) : (
|
||||||
|
<p className="text-gray-600 mr-auto pt-1 ml-2">
|
||||||
|
{translate('::' + gridDto?.gridOptions?.description)}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex gap-1">
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant={viewMode === 'grid' ? 'solid' : 'default'}
|
||||||
|
onClick={() => setViewMode('grid')}
|
||||||
|
title="Grid Görünümü"
|
||||||
|
>
|
||||||
|
<FaList className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant={viewMode === 'card' ? 'solid' : 'default'}
|
||||||
|
onClick={() => setViewMode('card')}
|
||||||
|
title="Kart Görünümü"
|
||||||
|
>
|
||||||
|
<FaTh className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{viewMode === 'grid' ? (
|
||||||
|
<Grid
|
||||||
|
listFormCode={listFormCode}
|
||||||
|
searchParams={searchParams}
|
||||||
|
isSubForm={false}
|
||||||
|
onGridDtoLoad={setGridDto}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<CardView listFormCode={listFormCode} searchParams={searchParams} />
|
||||||
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue