Projekt

Obecné

Profil

Stáhnout (6.76 KB) Statistiky
| Větev: | Tag: | Revize:
1
import {
2
    Link,
3
    Table,
4
    TableBody,
5
    TableCell,
6
    TableContainer,
7
    TableHead,
8
    TablePagination,
9
    TableRow,
10
    Typography,
11
} from '@mui/material'
12
import { Fragment, useEffect, useState } from 'react'
13
import { Link as RouterLink } from 'react-router-dom'
14
import { CatalogItemDto } from '../../swagger/data-contracts'
15
import ShowErrorIfPresent from '../Reusables/ShowErrorIfPresent'
16
import ContentLoading from '../Reusables/ContentLoading'
17
import { RootState } from '../redux/store'
18
import { useDispatch, useSelector } from 'react-redux'
19
import {
20
    consumeError,
21
    setLoading,
22
    setRowsPerPage,
23
    ShowAllItemsOption,
24
} from './catalogSlice'
25
import { fetchItems } from './catalogThunks'
26
import { formatHtmlStringToReactDom } from '../../utils/formatting/HtmlUtils'
27

    
28
// Catalog table component
29
const CatalogTable = () => {
30
    const [page, setPage] = useState(0) // currently shown page
31

    
32
    const dispatch = useDispatch()
33

    
34
    // Rows per page
35
    const rowsPerPageOptions = useSelector(
36
        (state: RootState) => state.catalog.rowsPerPageOptions
37
    )
38
    const rowsPerPage = useSelector(
39
        (state: RootState) => state.catalog.rowsPerPage
40
    )
41

    
42
    // Items, loading and error from api
43
    const items = useSelector((state: RootState) => state.catalog.items)
44
    const loading = useSelector((state: RootState) => state.catalog.loading)
45
    const apiError = useSelector((state: RootState) => state.catalog.error)
46

    
47
    // Local state to display any error relevant error
48
    const [displayError, setDisplayError] = useState<string | undefined>(
49
        undefined
50
    )
51
    const [unload, setUnload] = useState(true)
52

    
53
    // When changing rows per page set the selected number and reset to the first page
54
    const onRowsPerPageChange = (
55
        event: React.ChangeEvent<HTMLInputElement>
56
    ) => {
57
        dispatch(setRowsPerPage(Number(event.target.value)))
58
        setPage(0)
59
    }
60

    
61
    useEffect(() => {
62
        // Fetch items when the component is mounted
63
        // This will automatically search whenever the filter changes
64
        dispatch(fetchItems())
65

    
66
        return () => {
67
            // Invalidate the state when unmounting so that the old list is not rerendered when the user returns to the page
68
            dispatch(setLoading())
69
        }
70
    }, [dispatch])
71

    
72
    // Use effect to read the error and consume it
73
    useEffect(() => {
74
        if (apiError) {
75
            setDisplayError(apiError)
76
            dispatch(consumeError())
77
        }
78
    }, [apiError, dispatch])
79

    
80
    // Name of columns in the header
81
    const columns = [
82
        'Name',
83
        'Alternative Names',
84
        'Written form',
85
        'Type',
86
        'State or Territory',
87
        'Coordinates',
88
        'Certainty',
89
    ]
90

    
91
    const mapValueOrDefault = (value?: string, textStyle?: any) => (
92
        <TableCell align="center">
93
            <Typography
94
                sx={{
95
                    ...textStyle,
96
                }}
97
            >
98
                {formatHtmlStringToReactDom(value as string)}
99
            </Typography>
100
        </TableCell>
101
    )
102

    
103
    // Maps catalogItem to corresponding table row
104
    const mapItemColumnValues = (item: CatalogItemDto) => (
105
        <Fragment>
106
            {/* {mapValueOrDefault(item.name)} */}
107
            <TableCell align="center">
108
                <Link
109
                    component={RouterLink}
110
                    to={`/catalog/${item.id as string}`}
111
                    onClick={() => setUnload(false)}
112
                >
113
                    {item.name}
114
                </Link>
115
            </TableCell>
116
            {mapValueOrDefault(item.allNames?.join(', '), {
117
                display: '-webkit-box',
118
                overflow: 'hidden',
119
                WebkitBoxOrient: 'vertical',
120
                wordBreak: 'break-all',
121
                WebkitLineClamp: 2,
122
            })}
123
            {mapValueOrDefault(item.writtenForms?.join(', '))}
124
            {mapValueOrDefault(item.types?.join(', '))}
125
            {mapValueOrDefault(item.countries?.join(', '))}
126
            {mapValueOrDefault(
127
                item.latitude && item.longitude
128
                    ? `${item.latitude.toFixed(2)}, ${item.longitude.toFixed(
129
                          2
130
                      )}`
131
                    : undefined
132
            )}
133
            {mapValueOrDefault(
134
                item.certainty ? `${item.certainty}` : undefined
135
            )}
136
        </Fragment>
137
    )
138

    
139
    return (
140
        <Fragment>
141
            <ShowErrorIfPresent err={displayError} />
142
            {loading && !displayError ? <ContentLoading /> : null}
143
            {!loading && !displayError ? (
144
                <Fragment>
145
                    <TableContainer sx={{ minHeight: '65vh', maxHeight: '65vh' }}>
146
                        <Table
147
                            stickyHeader
148
                            sx={{ minWidth: 400 }}
149
                            aria-label="catalogTable"
150
                        >
151
                            <TableHead>
152
                                <TableRow>
153
                                    {columns.map((col, idx) => (
154
                                        <TableCell key={idx} align="center">
155
                                            {col}
156
                                        </TableCell>
157
                                    ))}
158
                                </TableRow>
159
                            </TableHead>
160
                            <TableBody>
161
                                {items
162
                                    .slice(
163
                                        page * rowsPerPage,
164
                                        page * rowsPerPage + rowsPerPage
165
                                    )
166
                                    .map((row, idx) => (
167
                                        <TableRow hover tabIndex={-1} key={idx}>
168
                                            {mapItemColumnValues(row)}
169
                                        </TableRow>
170
                                    ))}
171
                            </TableBody>
172
                        </Table>
173
                    </TableContainer>
174
                    <TablePagination
175
                        rowsPerPageOptions={rowsPerPageOptions.map((item) => ({
176
                            value:
177
                                item === ShowAllItemsOption
178
                                    ? items.length
179
                                    : item,
180
                            label: item as string,
181
                        }))}
182
                        component="div"
183
                        count={items.length}
184
                        rowsPerPage={rowsPerPage}
185
                        page={page}
186
                        onPageChange={(_, newPage) => setPage(newPage)}
187
                        onRowsPerPageChange={onRowsPerPageChange}
188
                    />
189
                </Fragment>
190
            ) : null}
191
        </Fragment>
192
    )
193
}
194

    
195
export default CatalogTable
(6-6/8)