Skip to content

Commit

Permalink
basic Post + Problem search and filter
Browse files Browse the repository at this point in the history
  • Loading branch information
rtrembecky committed Dec 3, 2024
1 parent 63e91ac commit a8d58c3
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 54 deletions.
30 changes: 30 additions & 0 deletions src/components/Admin/custom/FilterSidebar.tsx
Original file line number Diff line number Diff line change
@@ -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<PropsWithChildren> = ({children}) => {
const [filterOpen, setFilterOpen] = useState(true)
const toggleFilter = () => setFilterOpen((prev) => !prev)

return (
// TODO: fix collapsed state
<Stack sx={{order: -1, mr: 2, alignItems: 'start'}}>
<IconButton onClick={toggleFilter} sx={{m: 0.5}}>
<FilterListIcon />
</IconButton>

<Stack
sx={{
width: 200,
color: 'unset',
bgcolor: 'unset',
display: filterOpen ? 'block' : 'none',
}}
>
<FilterLiveSearch />
{children}
</Stack>
</Stack>
)
}
64 changes: 17 additions & 47 deletions src/components/Admin/dataProvider.ts
Original file line number Diff line number Diff line change
@@ -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<any[]>(`${apiUrl}/${resource}${stringifiedQuery ? `/?${stringifiedQuery}` : ''}`)

Check warning on line 28 in src/components/Admin/dataProvider.ts

View workflow job for this annotation

GitHub Actions / branch-test

Unexpected any. Specify a different type

// 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) => {
Expand All @@ -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)
}

Expand Down
25 changes: 19 additions & 6 deletions src/components/Admin/resources/cms/post/PostList.tsx
Original file line number Diff line number Diff line change
@@ -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 = () => (
<List>
<List aside={<PostListFilters />}>
<Datagrid>
<TextField source="caption" />
<TruncatedTextField source="short_text" maxTextWidth={50} />
<TruncatedTextField source="details" maxTextWidth={50} />
<TextField source="caption" sortable={false} />
<TruncatedTextField source="short_text" maxTextWidth={50} sortable={false} />
<TruncatedTextField source="details" maxTextWidth={50} sortable={false} />
<DateTimeField source="added_at" />
<DateTimeField source="visible_after" />
<DateTimeField source="visible_until" />
<SitesArrayField source="sites" />
<SitesArrayField source="sites" sortable={false} />
<FunctionField<RaRecord>
source="links"
label="Link count"
render={(record) => record && <span>{record['links'].length}</span>}
sortable={false}
/>
</Datagrid>
</List>
)

const PostListFilters: FC = () => (
<FilterSidebar>
<FilterList label="Seminár" icon={null}>
{seminarIds.map((seminarId) => (
<FilterListItem key={seminarId} label={seminarIdToName[seminarId]} value={{sites: seminarId}} />
))}
</FilterList>
</FilterSidebar>
)
Original file line number Diff line number Diff line change
@@ -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 = () => (
<List>
<List aside={<ProblemListFilters />}>
<Datagrid>
<ReferenceField source="series" reference="competition/series" link={false} />
<NumberField source="order" />
Expand All @@ -27,3 +34,20 @@ export const ProblemList: FC = () => (
</Datagrid>
</List>
)

const ProblemListFilters: FC = () => (
<FilterSidebar>
<FilterListSection label="Séria" icon={null}>
<FilterLiveForm>
<ReferenceInput source="series" reference="competition/series">
<AutocompleteInput helperText={false} />
</ReferenceInput>
</FilterLiveForm>
</FilterListSection>
<FilterList label="Číslo úlohy" icon={null}>
{[1, 2, 3, 4, 5, 6].map((problemNumber) => (
<FilterListItem key={problemNumber} label={problemNumber.toString()} value={{order: problemNumber}} />
))}
</FilterList>
</FilterSidebar>
)
2 changes: 2 additions & 0 deletions src/utils/useSeminarInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const seminarToId: Record<Seminar, SeminarId> = {
malynar: 2,
}

export const seminarIds = Object.values(seminarToId)

export const useSeminarInfo = () => {
const router = useRouter()

Expand Down

0 comments on commit a8d58c3

Please sign in to comment.