Projekt

Obecné

Profil

Stáhnout (6.66 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

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

    
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
39
    )
40

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

    
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)
51

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

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

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

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

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

    
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>
100
    )
101

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

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

    
194
export default CatalogTable
(5-5/7)