List teki Card üzeirnden değişiklikler
FormDevExpress kullanıldı. Tüm yetenekleriyle birlikte
This commit is contained in:
parent
e22ea52c6a
commit
4dc8ac1e47
8 changed files with 183 additions and 206 deletions
|
|
@ -16,6 +16,7 @@ import { GridExtraFilterState } from '../list/Utils'
|
|||
import { usePWA } from '@/utils/hooks/usePWA'
|
||||
|
||||
const FormButtons = (props: {
|
||||
isSubForm?: boolean
|
||||
mode: RowMode
|
||||
listFormCode: string
|
||||
id?: string
|
||||
|
|
@ -33,6 +34,7 @@ const FormButtons = (props: {
|
|||
onActionView?: () => void
|
||||
}) => {
|
||||
const {
|
||||
isSubForm,
|
||||
mode,
|
||||
listFormCode,
|
||||
id,
|
||||
|
|
@ -168,21 +170,24 @@ const FormButtons = (props: {
|
|||
{!!commandColumnData?.buttons?.filter((item) => typeof item !== 'string').length && (
|
||||
<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>
|
||||
|
||||
{!isSubForm && (
|
||||
<Button
|
||||
variant="solid"
|
||||
size="xs"
|
||||
color="gray-500"
|
||||
title={translate('::Cancel')}
|
||||
onClick={() => {
|
||||
if (onActionView && id) {
|
||||
onActionView()
|
||||
} else {
|
||||
navigate(-1)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FaBackward />
|
||||
</Button>
|
||||
)}
|
||||
{mode != 'new' && (
|
||||
<Button
|
||||
variant="solid"
|
||||
|
|
@ -267,7 +272,7 @@ const FormButtons = (props: {
|
|||
<FaSave />
|
||||
</Button>
|
||||
)}
|
||||
{checkPermission(gridDto?.gridOptions.permissionDto.c) && (
|
||||
{checkPermission(gridDto?.gridOptions.permissionDto.c) && !isSubForm && (
|
||||
<Button
|
||||
variant="solid"
|
||||
color="green-500"
|
||||
|
|
|
|||
|
|
@ -66,10 +66,11 @@ const FormEdit = (
|
|||
defaultTitle="Sözsoft Kurs Platform"
|
||||
></Helmet>
|
||||
)}
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h3>{translate('::' + gridDto?.gridOptions.title)}</h3>
|
||||
<div className={`flex items-center mb-2 ${isSubForm ? 'justify-center' : 'justify-between'}`}>
|
||||
{!isSubForm && <h3>{translate('::' + gridDto?.gridOptions.title)}</h3>}
|
||||
{permissionResults && (
|
||||
<FormButtons
|
||||
isSubForm={isSubForm}
|
||||
mode={mode}
|
||||
listFormCode={listFormCode}
|
||||
id={formData?.Id}
|
||||
|
|
@ -94,7 +95,6 @@ const FormEdit = (
|
|||
formItems={formItems}
|
||||
setFormData={setFormData}
|
||||
/>
|
||||
<hr className="my-2" />
|
||||
<SubForms gridDto={gridDto!} formData={formData} level={level ?? 0} />
|
||||
</Container>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -152,12 +152,11 @@ const FormNew = (
|
|||
defaultTitle="Sözsoft Kurs Platform"
|
||||
></Helmet>
|
||||
)}
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3>
|
||||
{translate('::AddNew')} {translate('::App.Languages.Language')}
|
||||
</h3>
|
||||
<div className={`flex items-center mb-2 ${isSubForm ? 'justify-center' : 'justify-between'}`}>
|
||||
{!isSubForm && <h3>{translate('::' + gridDto?.gridOptions.title)}</h3>}
|
||||
{permissionResults && (
|
||||
<FormButtons
|
||||
isSubForm={isSubForm}
|
||||
mode={mode}
|
||||
listFormCode={listFormCode}
|
||||
id={formData?.Id}
|
||||
|
|
|
|||
|
|
@ -61,10 +61,11 @@ const FormView = (
|
|||
defaultTitle="Sözsoft Kurs Platform"
|
||||
></Helmet>
|
||||
)}
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h3>{translate('::' + gridDto?.gridOptions.title)}</h3>
|
||||
<div className={`flex items-center mb-2 ${isSubForm ? 'justify-center' : 'justify-between'}`}>
|
||||
{!isSubForm && <h3>{translate('::' + gridDto?.gridOptions.title)}</h3>}
|
||||
{permissionResults && (
|
||||
<FormButtons
|
||||
isSubForm={isSubForm}
|
||||
mode={mode}
|
||||
listFormCode={listFormCode}
|
||||
id={formData?.Id}
|
||||
|
|
@ -89,7 +90,6 @@ const FormView = (
|
|||
formItems={formItems}
|
||||
setFormData={() => {}}
|
||||
/>
|
||||
<hr className="my-2" />
|
||||
<SubForms gridDto={gridDto!} formData={formData} level={level ?? 0} refreshData={fetchData} />
|
||||
</Container>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ const SubForms = (props: {
|
|||
}
|
||||
}
|
||||
}}
|
||||
className='mt-2'
|
||||
>
|
||||
<TabList>
|
||||
{subForms.map((subForm, i) => {
|
||||
|
|
|
|||
149
ui/src/views/list/Card.tsx
Normal file
149
ui/src/views/list/Card.tsx
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { GridDto } from '@/proxy/form/models'
|
||||
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
|
||||
import { Pagination, Select } from '@/components/ui'
|
||||
import classNames from 'classnames'
|
||||
import { getList } from '@/services/form.service'
|
||||
import { FaInbox } from 'react-icons/fa'
|
||||
import FormView from '../form/FormView'
|
||||
|
||||
interface CardProps {
|
||||
listFormCode: string
|
||||
searchParams?: URLSearchParams
|
||||
}
|
||||
|
||||
type Option = {
|
||||
value: number
|
||||
label: string
|
||||
}
|
||||
|
||||
const CardItem = ({
|
||||
row,
|
||||
gridDto,
|
||||
listFormCode,
|
||||
}: {
|
||||
row: any
|
||||
gridDto: GridDto
|
||||
listFormCode: string
|
||||
}) => {
|
||||
const keyField = gridDto.gridOptions.keyFieldName
|
||||
const rowId = row[keyField!]
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-neutral-800 border dark:border-neutral-700 flex flex-col p-4">
|
||||
<div className="flex-grow">
|
||||
<FormView listFormCode={listFormCode} id={rowId} isSubForm={true} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Card = ({ listFormCode, searchParams }: CardProps) => {
|
||||
const { createSelectDataSource } = useListFormCustomDataSource({})
|
||||
const [gridDto, setGridDto] = useState<GridDto>()
|
||||
const [data, setData] = useState<any[]>([])
|
||||
const [totalCount, setTotalCount] = useState(0)
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [pageSize, setPageSize] = useState(20)
|
||||
const [pageSizeOptions, setPageSizeOptions] = useState<Option[]>([])
|
||||
|
||||
const onPageSizeSelect = ({ value }: Option) => {
|
||||
setPageSize(value)
|
||||
setCurrentPage(1)
|
||||
}
|
||||
|
||||
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 allowedSizes =
|
||||
pagerOptions?.allowedPageSizes
|
||||
?.split(',')
|
||||
.map((s) => Number(s.trim()))
|
||||
.filter((n) => !isNaN(n) && n > 0) || [20, 50, 100]
|
||||
|
||||
setPageSizeOptions(allowedSizes.map((size) => ({ value: size, label: `${size} page` })))
|
||||
}, [gridDto, listFormCode, searchParams])
|
||||
|
||||
useEffect(() => {
|
||||
loadData()
|
||||
}, [loadData])
|
||||
|
||||
if (!gridDto) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
{data.length === 0 && (
|
||||
<div className="flex flex-col items-center justify-center p-10 bg-gray-50 dark:bg-neutral-800/50 rounded-md border-2 border-dashed border-gray-200 dark:border-neutral-700">
|
||||
<div className="text-center">
|
||||
<FaInbox className="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />
|
||||
<p className="mt-4 text-lg font-semibold text-gray-700 dark:text-gray-300">
|
||||
Kayıt Bulunamadı
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 mt-1">
|
||||
Görüntülenecek herhangi bir veri yok.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-4 gap-4">
|
||||
{data.map((row, idx) => {
|
||||
const keyField = gridDto.gridOptions.keyFieldName
|
||||
const rowId = row[keyField!]
|
||||
|
||||
return <CardItem key={rowId || idx} row={row} gridDto={gridDto} listFormCode={listFormCode} />
|
||||
})}
|
||||
</div>
|
||||
|
||||
{gridDto.gridOptions.pagerOptionDto?.visible && totalCount > pageSize && (
|
||||
<div className={classNames('flex items-center justify-between border-t-1 gap-4 mt-4')}>
|
||||
<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 Card
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
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, FaInbox } 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 (
|
||||
<>
|
||||
{data.length === 0 && (
|
||||
<div className="flex flex-col items-center justify-center p-10 bg-gray-50 dark:bg-neutral-800/50 rounded-md border-2 border-dashed border-gray-200 dark:border-neutral-700">
|
||||
<div className="text-center">
|
||||
<FaInbox className="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />
|
||||
<p className="mt-4 text-lg font-semibold text-gray-700 dark:text-gray-300">Kayıt Bulunamadı</p>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 mt-1">Görüntülenecek herhangi bir veri yok.</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<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
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { useLocation, useParams, useSearchParams } from 'react-router-dom'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useState } from 'react'
|
||||
import Container from '@/components/shared/Container'
|
||||
import Grid from './Grid'
|
||||
import { FaList, FaTh, FaUser } from 'react-icons/fa'
|
||||
|
|
@ -7,10 +7,9 @@ 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'
|
||||
import Card from './Card'
|
||||
import { Button } from '@/components/ui'
|
||||
import navigationIcon from '@/configs/navigation-icon.config'
|
||||
import { NavigationTree } from '@/@types/navigation'
|
||||
import { navigationTreeToFlat } from '@/utils/navigation'
|
||||
|
||||
const List = () => {
|
||||
|
|
@ -86,7 +85,7 @@ const List = () => {
|
|||
onGridDtoLoad={setGridDto}
|
||||
/>
|
||||
) : (
|
||||
<CardView listFormCode={listFormCode} searchParams={searchParams} />
|
||||
<Card listFormCode={listFormCode} searchParams={searchParams} />
|
||||
)}
|
||||
</Container>
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue