Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tables: store visible columns and max rows #3168

Merged
merged 7 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions webapp/components/Table/Footer/Footer.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import React from 'react'
import { useNavigate } from 'react-router'
import { useDispatch } from 'react-redux'
import PropTypes from 'prop-types'

import { Objects } from '@openforis/arena-core'

import { updateQuery } from '@webapp/components/Table/tableLink'

import Paginator from './Paginator'
import { TablesActions } from '@webapp/store/ui/tables'

export const Footer = (props) => {
const { list, offset, limit, count } = props
const { count, limit, list, module, offset } = props

const dispatch = useDispatch()
const navigate = useNavigate()

return (
Expand All @@ -19,10 +23,21 @@ export const Footer = (props) => {
offset={offset}
limit={limit}
count={count}
setLimit={(limitUpdated) => updateQuery(navigate)({ limit: limitUpdated })}
setLimit={(limitUpdated) => {
updateQuery(navigate)({ limit: limitUpdated })
dispatch(TablesActions.updateMaxRows({ module, maxRows: limitUpdated }))
}}
setOffset={(offsetUpdated) => updateQuery(navigate)({ offset: offsetUpdated })}
/>
)}
</div>
)
}

Footer.propTypes = {
count: PropTypes.number.isRequired,
limit: PropTypes.number.isRequired,
list: PropTypes.array,
module: PropTypes.string.isRequired,
offset: PropTypes.number.isRequired,
}
9 changes: 4 additions & 5 deletions webapp/components/Table/Footer/Paginator/Paginator.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@ const Paginator = (props) => {
itemLabel={A.identity}
selection={limit}
onChange={(limitUpdated) => {
if (TableConstants.itemsPerPageValues.includes(Number(limitUpdated))) {
setLimit(limitUpdated)
} else {
setLimit(TableConstants.itemsPerPageDefault)
}
const limitNext = TableConstants.itemsPerPageValues.includes(Number(limitUpdated))
? limitUpdated
: TableConstants.itemsPerPageDefault
setLimit(limitNext)
}}
/>
</div>
Expand Down
8 changes: 7 additions & 1 deletion webapp/components/Table/Header/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ const Header = (props) => {
onVisibleColumnsChange,
totalCount,
visibleColumnsSelectionEnabled,
visibleColumnKeys,
} = props

return (
<div className="table__header">
{React.createElement(headerLeftComponent, { ...props, ...headerProps })}
{visibleColumnsSelectionEnabled && totalCount > 0 && (
<VisibleColumnsMenu columns={columns} onSelectionChange={onVisibleColumnsChange} />
<VisibleColumnsMenu
columns={columns}
onSelectionChange={onVisibleColumnsChange}
selectedColumnKeys={visibleColumnKeys}
/>
)}
</div>
)
Expand All @@ -34,6 +39,7 @@ Header.propTypes = {
onVisibleColumnsChange: PropTypes.func.isRequired,
totalCount: PropTypes.number.isRequired,
visibleColumnsSelectionEnabled: PropTypes.bool,
visibleColumnKeys: PropTypes.array.isRequired,
}

Header.defaultProps = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import './VisibleColumnsMenu.scss'

import React, { useCallback, useState } from 'react'
import React, { useCallback } from 'react'
import PropTypes from 'prop-types'

import { Objects } from '@openforis/arena-core'
Expand All @@ -11,16 +11,13 @@ import { ButtonMenu } from '@webapp/components'
import { Checkbox } from '@webapp/components/form'

export const VisibleColumnsMenu = (props) => {
const { columns, onSelectionChange } = props
const { columns, onSelectionChange, selectedColumnKeys } = props

const availableColumns = columns.filter((column) => !Objects.isEmpty(column.header) && column.header !== '#')

const [selectedColumnKeys, setSelectedColumnKeys] = useState(columns.map((col) => col.key))

const onColummSelectionChange = useCallback(
(key) => () => {
const selectedColumnKeysNext = ArrayUtils.addOrRemoveItem({ item: key })(selectedColumnKeys)
setSelectedColumnKeys(selectedColumnKeysNext)
onSelectionChange(selectedColumnKeysNext)
},
[onSelectionChange, selectedColumnKeys]
Expand Down Expand Up @@ -55,4 +52,5 @@ export const VisibleColumnsMenu = (props) => {
VisibleColumnsMenu.propTypes = {
columns: PropTypes.array.isRequired,
onSelectionChange: PropTypes.func.isRequired,
selectedColumnKeys: PropTypes.array,
}
4 changes: 3 additions & 1 deletion webapp/components/Table/Table.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const Table = (props) => {
onRowClick,
onVisibleColumnsChange,
selectedItems,
visibleColumnKeys,
visibleColumns,
} = useTable({
columns,
Expand Down Expand Up @@ -84,6 +85,7 @@ const Table = (props) => {
onVisibleColumnsChange={onVisibleColumnsChange}
selectedItems={selectedItems}
visibleColumnsSelectionEnabled={visibleColumnsSelectionEnabled}
visibleColumnKeys={visibleColumnKeys}
/>

<Content
Expand Down Expand Up @@ -114,7 +116,7 @@ const Table = (props) => {
handleSortBy={handleSortBy}
selectedItems={selectedItems}
/>
<Footer offset={offset} list={list} limit={limit} count={count} />
<Footer count={count} limit={limit} list={list} module={module} offset={offset} />
</div>
)
}
Expand Down
2 changes: 1 addition & 1 deletion webapp/components/Table/constants.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const TableConstants = {
itemsPerPageDefault: 30,
itemsPerPageValues: [15, 30, 50],
itemsPerPageValues: [15, 30, 50, 100],
}
31 changes: 24 additions & 7 deletions webapp/components/Table/useTable.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { useEffect, useCallback, useState } from 'react'
import { useEffect, useCallback, useState, useMemo } from 'react'
import { useNavigate } from 'react-router'
import { useDispatch } from 'react-redux'

import { ArrayUtils } from '@core/arrayUtils'

import { useSurveyId } from '@webapp/store/survey'
import { useAsyncGetRequest, useOnUpdate } from '@webapp/components/hooks'
import { getLimit, getOffset, getSearch, getSort, updateQuery } from '@webapp/components/Table/tableLink'
import { ArrayUtils } from '@core/arrayUtils'
import { TablesActions, useTableMaxRows, useTableVisibleColumns } from '@webapp/store/ui/tables'

export const useTable = ({
columns,
Expand All @@ -15,15 +18,28 @@ export const useTable = ({
onRowClick: onRowClickProp,
selectable,
}) => {
const dispatch = useDispatch()

const [totalCount, setTotalCount] = useState(0)
const [visibleColumns, setVisibleColumns] = useState(columns)

const visibleColumnKeysInStore = useTableVisibleColumns(module)
const visibleColumnKeys = useMemo(
() => visibleColumnKeysInStore ?? columns?.map((column) => column.key) ?? [],
[columns, visibleColumnKeysInStore]
)
const visibleColumns = useMemo(
() => columns?.filter((column) => visibleColumnKeys.includes(column.key)) ?? [],
[columns, visibleColumnKeys]
)
const limitInState = useTableMaxRows(module)
const limitInLink = getLimit()
const limit = limitInState ?? limitInLink

const navigate = useNavigate()
const surveyId = useSurveyId()
const apiUri = moduleApiUri || `/api/survey/${surveyId}/${module}`

const offset = getOffset()
const limit = getLimit()
const sort = getSort()
const search = getSearch()

Expand Down Expand Up @@ -117,10 +133,10 @@ export const useTable = ({
)

const onVisibleColumnsChange = useCallback(
(visibleColumnKeys) => {
setVisibleColumns(columns.filter((column) => visibleColumnKeys.includes(column.key)))
(visibleColumnKeysUpdated) => {
dispatch(TablesActions.updateVisibleColumns({ module, visibleColumns: visibleColumnKeysUpdated }))
},
[columns]
[module]
)

return {
Expand All @@ -139,6 +155,7 @@ export const useTable = ({
onRowClick,
onVisibleColumnsChange,
selectedItems,
visibleColumnKeys,
visibleColumns,
}
}
2 changes: 2 additions & 0 deletions webapp/store/ui/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { LoaderReducer, LoaderState } from './loader'
import { DialogConfirmReducer, DialogConfirmState } from './dialogConfirm'
import { RecordReducer, RecordState } from './record'
import { SurveyFormReducer, SurveyFormState } from './surveyForm'
import { TablesReducer, TablesState } from './tables'
import { ChainReducer } from './chain'

export default combineReducers({
Expand All @@ -15,5 +16,6 @@ export default combineReducers({
[DialogConfirmState.stateKey]: DialogConfirmReducer,
[RecordState.stateKey]: RecordReducer,
[SurveyFormState.stateKey]: SurveyFormReducer,
[TablesState.stateKey]: TablesReducer,
chain: ChainReducer,
})
12 changes: 12 additions & 0 deletions webapp/store/ui/tables/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const tableVisibleColumnsUpdate = 'tables/visibleColumnsUpdate'
export const tableMaxRowsUpdate = 'tables/maxRowsUpdate'

export const updateVisibleColumns =
({ module, visibleColumns }) =>
(dispatch) =>
dispatch({ type: tableVisibleColumnsUpdate, module, visibleColumns })

export const updateMaxRows =
({ module, maxRows }) =>
(dispatch) =>
dispatch({ type: tableMaxRowsUpdate, module, maxRows })
6 changes: 6 additions & 0 deletions webapp/store/ui/tables/hooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { useSelector } from 'react-redux'
import * as TablesState from './state'

export const useTableMaxRows = (module) => useSelector(TablesState.getMaxRows(module))

export const useTableVisibleColumns = (module) => useSelector(TablesState.getVisibleColumns(module))
6 changes: 6 additions & 0 deletions webapp/store/ui/tables/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as TablesActions from './actions'
import TablesReducer from './reducer'
import * as TablesState from './state'

export { TablesActions, TablesReducer, TablesState }
export { useTableMaxRows, useTableVisibleColumns } from './hooks'
20 changes: 20 additions & 0 deletions webapp/store/ui/tables/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { exportReducer } from '@webapp/utils/reduxUtils'

import { SystemActions } from '@webapp/store/system'

import * as TablesActions from './actions'
import * as TablesState from './state'

const actionHandlers = {
// Reset form
[SystemActions.SYSTEM_RESET]: () => ({}),

// Tables
[TablesActions.tableVisibleColumnsUpdate]: (state, { module, visibleColumns }) =>
TablesState.assocVisibleColumns({ module, visibleColumns })(state),

[TablesActions.tableMaxRowsUpdate]: (state, { module, maxRows }) =>
TablesState.assocMaxRows({ module, maxRows })(state),
}

export default exportReducer(actionHandlers)
27 changes: 27 additions & 0 deletions webapp/store/ui/tables/state.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as A from '@core/arena'

import * as UiState from '../state'
import { Objects } from '@openforis/arena-core'

export const stateKey = 'tables'

const getState = A.pipe(UiState.getState, A.propOr({}, stateKey))

const keys = {
visibleColumnKeysByModule: 'visibleColumnKeysByModule',
maxRowsByModule: 'maxRowsByModule',
}

export const getVisibleColumns = (module) => A.pipe(getState, Objects.path([keys.visibleColumnKeysByModule, module]))

export const getMaxRows = (module) => A.pipe(getState, Objects.path([keys.maxRowsByModule, module]))

export const assocVisibleColumns =
({ module, visibleColumns }) =>
(state) =>
Objects.assocPath({ obj: state, path: [keys.visibleColumnKeysByModule, module], value: visibleColumns })

export const assocMaxRows =
({ module, maxRows }) =>
(state) =>
Objects.assocPath({ obj: state, path: [keys.maxRowsByModule, module], value: maxRows })
Loading