Revize 8754af5c
Přidáno uživatelem Václav Honzík před asi 2 roky(ů)
frontend/src/features/Catalog/CatalogTable.tsx | ||
---|---|---|
7 | 7 |
TableHead, |
8 | 8 |
TablePagination, |
9 | 9 |
TableRow, |
10 |
Typography, |
|
10 | 11 |
} from '@mui/material' |
11 | 12 |
import { Fragment, useEffect, useState } from 'react' |
12 | 13 |
import { Link as RouterLink } from 'react-router-dom' |
... | ... | |
15 | 16 |
import ContentLoading from '../Reusables/ContentLoading' |
16 | 17 |
import { RootState } from '../redux/store' |
17 | 18 |
import { useDispatch, useSelector } from 'react-redux' |
18 |
import { consumeError, setLoading } from './catalogSlice' |
|
19 |
import { |
|
20 |
consumeError, |
|
21 |
setLoading, |
|
22 |
setRowsPerPage, |
|
23 |
ShowAllItemsOption, |
|
24 |
} from './catalogSlice' |
|
19 | 25 |
import { fetchItems } from './catalogThunks' |
20 | 26 |
|
21 | 27 |
// Catalog table component |
22 | 28 |
const CatalogTable = () => { |
23 | 29 |
const [page, setPage] = useState(0) // currently shown page |
24 |
const rowsPerPage = [5, 10, 15, 20] // number of rows per page |
|
25 | 30 |
|
26 |
// Selected rows per page |
|
27 |
const [selectedRowsPerPage, setSelectedRowsPerPage] = useState( |
|
28 |
rowsPerPage[0] |
|
31 |
const dispatch = useDispatch() |
|
32 |
|
|
33 |
// Rows per page |
|
34 |
const rowsPerPageOptions = useSelector( |
|
35 |
(state: RootState) => state.catalog.rowsPerPageOptions |
|
36 |
) |
|
37 |
const rowsPerPage = useSelector( |
|
38 |
(state: RootState) => state.catalog.rowsPerPage |
|
29 | 39 |
) |
30 | 40 |
|
31 |
// Subscribe to the store
|
|
41 |
// Items, loading and error from api
|
|
32 | 42 |
const items = useSelector((state: RootState) => state.catalog.items) |
33 | 43 |
const loading = useSelector((state: RootState) => state.catalog.loading) |
34 | 44 |
const apiError = useSelector((state: RootState) => state.catalog.error) |
35 | 45 |
|
36 |
const [displayError, setDisplayError] = useState<string | undefined>(undefined) |
|
46 |
// Local state to display any error relevant error |
|
47 |
const [displayError, setDisplayError] = useState<string | undefined>( |
|
48 |
undefined |
|
49 |
) |
|
50 |
const [unload, setUnload] = useState(true) |
|
37 | 51 |
|
38 | 52 |
// When changing rows per page set the selected number and reset to the first page |
39 | 53 |
const onRowsPerPageChange = ( |
40 | 54 |
event: React.ChangeEvent<HTMLInputElement> |
41 | 55 |
) => { |
42 |
setSelectedRowsPerPage(Number(event.target.value))
|
|
56 |
dispatch(setRowsPerPage(Number(event.target.value)))
|
|
43 | 57 |
setPage(0) |
44 | 58 |
} |
45 | 59 |
|
46 |
const dispatch = useDispatch() |
|
47 |
|
|
48 | 60 |
useEffect(() => { |
49 | 61 |
// Fetch items when the component is mounted |
50 | 62 |
// This will automatically search whenever the filter changes |
... | ... | |
64 | 76 |
} |
65 | 77 |
}, [apiError, dispatch]) |
66 | 78 |
|
67 |
|
|
68 | 79 |
// Name of columns in the header |
69 | 80 |
const columns = [ |
70 | 81 |
'Name', |
... | ... | |
76 | 87 |
'Certainty', |
77 | 88 |
] |
78 | 89 |
|
79 |
const mapValueOrDefault = (value?: string) => ( |
|
80 |
<TableCell align="center">{value || 'N/A'}</TableCell> |
|
90 |
const mapValueOrDefault = (value?: string, textStyle?: any) => ( |
|
91 |
<TableCell align="center"> |
|
92 |
<Typography |
|
93 |
sx={{ |
|
94 |
...textStyle, |
|
95 |
}} |
|
96 |
> |
|
97 |
{value || 'N/A'} |
|
98 |
</Typography> |
|
99 |
</TableCell> |
|
81 | 100 |
) |
82 | 101 |
|
83 | 102 |
// Maps catalogItem to corresponding table row |
... | ... | |
88 | 107 |
<Link |
89 | 108 |
component={RouterLink} |
90 | 109 |
to={`/catalog/${item.id as string}`} |
110 |
onClick={() => setUnload(false)} |
|
91 | 111 |
> |
92 | 112 |
{item.name} |
93 | 113 |
</Link> |
94 | 114 |
</TableCell> |
95 |
{mapValueOrDefault(item.alternativeNames?.join(', '))} |
|
115 |
{mapValueOrDefault(item.alternativeNames?.join(', '), { |
|
116 |
display: '-webkit-box', |
|
117 |
overflow: 'hidden', |
|
118 |
WebkitBoxOrient: 'vertical', |
|
119 |
wordBreak: 'break-all', |
|
120 |
WebkitLineClamp: 2, |
|
121 |
})} |
|
96 | 122 |
{mapValueOrDefault(item.writtenForms?.join(', '))} |
97 | 123 |
{mapValueOrDefault(item.types?.join(', '))} |
98 | 124 |
{mapValueOrDefault(item.countries?.join(', '))} |
99 | 125 |
{mapValueOrDefault( |
100 | 126 |
item.latitude && item.longitude |
101 |
? `${item.latitude}, ${item.longitude}` |
|
127 |
? `${item.latitude.toFixed(2)}, ${item.longitude.toFixed( |
|
128 |
2 |
|
129 |
)}` |
|
102 | 130 |
: undefined |
103 | 131 |
)} |
104 | 132 |
{mapValueOrDefault( |
... | ... | |
112 | 140 |
<ShowErrorIfPresent err={displayError} /> |
113 | 141 |
{loading && !displayError ? <ContentLoading /> : null} |
114 | 142 |
{!loading && !displayError ? ( |
115 |
<Fragment>
|
|
116 |
<TableContainer> |
|
143 |
<Fragment> |
|
144 |
<TableContainer sx={{ minHeight: '50vh', maxHeight: '50vh' }}>
|
|
117 | 145 |
<Table |
118 | 146 |
stickyHeader |
119 | 147 |
sx={{ minWidth: 400 }} |
... | ... | |
131 | 159 |
<TableBody> |
132 | 160 |
{items |
133 | 161 |
.slice( |
134 |
page * rowsPerPage[0],
|
|
135 |
page * rowsPerPage[0] + rowsPerPage[0]
|
|
162 |
page * rowsPerPage, |
|
163 |
page * rowsPerPage + rowsPerPage
|
|
136 | 164 |
) |
137 | 165 |
.map((row, idx) => ( |
138 | 166 |
<TableRow hover tabIndex={-1} key={idx}> |
... | ... | |
143 | 171 |
</Table> |
144 | 172 |
</TableContainer> |
145 | 173 |
<TablePagination |
146 |
rowsPerPageOptions={rowsPerPage} |
|
174 |
rowsPerPageOptions={rowsPerPageOptions.map((item) => ({ |
|
175 |
value: |
|
176 |
item === ShowAllItemsOption |
|
177 |
? items.length |
|
178 |
: item, |
|
179 |
label: item as string, |
|
180 |
}))} |
|
147 | 181 |
component="div" |
148 | 182 |
count={items.length} |
149 |
rowsPerPage={selectedRowsPerPage}
|
|
183 |
rowsPerPage={rowsPerPage}
|
|
150 | 184 |
page={page} |
151 | 185 |
onPageChange={(_, newPage) => setPage(newPage)} |
152 | 186 |
onRowsPerPageChange={onRowsPerPageChange} |
Také k dispozici: Unified diff
Table scrolling
re #9534