From a8d58c3a5d4099ee784a747a40e1c1929ee91bca Mon Sep 17 00:00:00 2001 From: rtrembecky Date: Mon, 2 Dec 2024 21:48:26 +0100 Subject: [PATCH] basic Post + Problem search and filter --- src/components/Admin/custom/FilterSidebar.tsx | 30 +++++++++ src/components/Admin/dataProvider.ts | 64 +++++-------------- .../Admin/resources/cms/post/PostList.tsx | 25 ++++++-- .../competition/problems/ProblemList.tsx | 26 +++++++- src/utils/useSeminarInfo.ts | 2 + 5 files changed, 93 insertions(+), 54 deletions(-) create mode 100644 src/components/Admin/custom/FilterSidebar.tsx diff --git a/src/components/Admin/custom/FilterSidebar.tsx b/src/components/Admin/custom/FilterSidebar.tsx new file mode 100644 index 00000000..3a3568e8 --- /dev/null +++ b/src/components/Admin/custom/FilterSidebar.tsx @@ -0,0 +1,30 @@ +import {FilterList as FilterListIcon} from '@mui/icons-material' +import {IconButton, Stack} from '@mui/material' +import {FC, PropsWithChildren, useState} from 'react' +import {FilterLiveSearch} from 'react-admin' + +export const FilterSidebar: FC = ({children}) => { + const [filterOpen, setFilterOpen] = useState(true) + const toggleFilter = () => setFilterOpen((prev) => !prev) + + return ( + // TODO: fix collapsed state + + + + + + + + {children} + + + ) +} diff --git a/src/components/Admin/dataProvider.ts b/src/components/Admin/dataProvider.ts index c5a71589..4ba03273 100644 --- a/src/components/Admin/dataProvider.ts +++ b/src/components/Admin/dataProvider.ts @@ -1,59 +1,36 @@ import axios from 'axios' import {stringify} from 'querystring' -import {DataProvider, RaRecord} from 'react-admin' -// TODO: BE chysta search, filter, pagination a sort. ked to bude ready, -// postupne odkomentujeme tento kod a zmazeme client-side handling nizsie -// import {FilterPayload, PaginationPayload, SortPayload} from 'react-admin' - +import {DataProvider, FilterPayload, /* PaginationPayload, */ RaRecord, SortPayload} from 'react-admin' + +const getFilterQuery = ({q, ...otherSearchParams}: FilterPayload) => ({ + ...otherSearchParams, + search: q, +}) +const getOrderingQuery = ({order, field}: SortPayload) => ({ordering: `${order === 'ASC' ? '' : '-'}${field}`}) +// TODO: pagination podla BE // const getPaginationQuery = ({page, perPage}: PaginationPayload) => ({ // offset: page, // limit: perPage, // }) -// const getFilterQuery = ({q, ...otherSearchParams}: FilterPayload) => ({ -// ...otherSearchParams, -// search: q, -// }) -// const getOrderingQuery = ({field, order}: SortPayload) => ({ -// ordering: `${order === 'ASC' ? '' : '-'}${field}`, -// }) - -const dynamicSort = (key: string, order: string) => { - const orderValue = order === 'ASC' ? 1 : -1 - return (a: RaRecord, b: RaRecord) => { - if (a[key] > b[key]) return orderValue - if (a[key] < b[key]) return -orderValue - return 0 - } -} const apiUrl = '/api' // skopirovane a dost upravene z https://github.com/bmihelac/ra-data-django-rest-framework/blob/master/src/index.ts export const dataProvider: DataProvider = { - getList: async (resource, params) => { + getList: async (resource, {filter, sort, pagination}) => { const query = { - // TODO: ked BE bude mat pagination, filter alebo sort - // ...getFilterQuery(params.filter), - // ...getPaginationQuery(params.pagination), - // ...getOrderingQuery(params.sort), + ...(filter ? getFilterQuery(filter) : {}), + ...(sort ? getOrderingQuery(sort) : {}), + // TODO: pagination podla BE + // ...getPaginationQuery(pagination), } const stringifiedQuery = stringify(query) const {data} = await axios.get(`${apiUrl}/${resource}${stringifiedQuery ? `/?${stringifiedQuery}` : ''}`) // client-side filter let filteredData = data - if (params.filter) { - const {q: search, ...rest} = params.filter - if (search) { - // vyhladava to filter string vo vsetkych fieldoch kazdeho recordu - // - bohuzial tie fieldy su casto len IDcka inych modelov, tak nic moc :D - filteredData = data.filter((record: RaRecord) => { - const matches = Object.values(record).some((value) => { - return value && JSON.stringify(value).toLowerCase().includes(search.toLowerCase()) - }) - return matches - }) - } + if (filter) { + const {q, ...rest} = filter if (rest) { filteredData = filteredData.filter((record: RaRecord) => { @@ -65,17 +42,10 @@ export const dataProvider: DataProvider = { } } - // client-side sort - if (params.sort) { - const {field, order} = params.sort - - filteredData.sort(dynamicSort(field, order)) - } - // client-side pagination let pagedData = filteredData - if (params.pagination) { - const {page, perPage} = params.pagination + if (pagination) { + const {page, perPage} = pagination pagedData = filteredData.slice((page - 1) * perPage, page * perPage) } diff --git a/src/components/Admin/resources/cms/post/PostList.tsx b/src/components/Admin/resources/cms/post/PostList.tsx index 11956552..a10e4db0 100644 --- a/src/components/Admin/resources/cms/post/PostList.tsx +++ b/src/components/Admin/resources/cms/post/PostList.tsx @@ -1,25 +1,38 @@ import {FC} from 'react' -import {Datagrid, FunctionField, List, RaRecord, TextField} from 'react-admin' +import {Datagrid, FilterList, FilterListItem, FunctionField, List, RaRecord, TextField} from 'react-admin' import {DateTimeField} from '@/components/Admin/custom/DateTimeField' +import {FilterSidebar} from '@/components/Admin/custom/FilterSidebar' import {SitesArrayField} from '@/components/Admin/custom/SitesArrayField' import {TruncatedTextField} from '@/components/Admin/custom/TruncatedTextField' +import {seminarIds, seminarIdToName} from '@/utils/useSeminarInfo' export const PostList: FC = () => ( - + }> - - - + + + - + source="links" label="Link count" render={(record) => record && {record['links'].length}} + sortable={false} /> ) + +const PostListFilters: FC = () => ( + + + {seminarIds.map((seminarId) => ( + + ))} + + +) diff --git a/src/components/Admin/resources/competition/problems/ProblemList.tsx b/src/components/Admin/resources/competition/problems/ProblemList.tsx index 325594d5..d2da9d61 100644 --- a/src/components/Admin/resources/competition/problems/ProblemList.tsx +++ b/src/components/Admin/resources/competition/problems/ProblemList.tsx @@ -1,19 +1,26 @@ import {FC} from 'react' import { + AutocompleteInput, BooleanField, Datagrid, + FilterList, + FilterListItem, + FilterListSection, + FilterLiveForm, FunctionField, ImageField, List, NumberField, RaRecord, ReferenceField, + ReferenceInput, } from 'react-admin' +import {FilterSidebar} from '@/components/Admin/custom/FilterSidebar' import {TruncatedTextField} from '@/components/Admin/custom/TruncatedTextField' export const ProblemList: FC = () => ( - + }> @@ -27,3 +34,20 @@ export const ProblemList: FC = () => ( ) + +const ProblemListFilters: FC = () => ( + + + + + + + + + + {[1, 2, 3, 4, 5, 6].map((problemNumber) => ( + + ))} + + +) diff --git a/src/utils/useSeminarInfo.ts b/src/utils/useSeminarInfo.ts index 45145018..2c9465c0 100644 --- a/src/utils/useSeminarInfo.ts +++ b/src/utils/useSeminarInfo.ts @@ -9,6 +9,8 @@ const seminarToId: Record = { malynar: 2, } +export const seminarIds = Object.values(seminarToId) + export const useSeminarInfo = () => { const router = useRouter()