cspace-ui
Version:
CollectionSpace user interface for browsers
160 lines (140 loc) • 4.79 kB
JSX
import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import { useSelector } from 'react-redux';
import get from 'lodash/get';
import Immutable from 'immutable';
import SearchResultTableHeader from './SearchResultTableHeader';
import { getColumnConfig, readListItems } from '../searchResultHelpers';
import { getSearchResult, getSearchSelectedItems } from '../../../reducers';
import { SEARCH_RESULT_PAGE_SEARCH_NAME } from '../../../constants/searchNames';
import { useConfig } from '../../config/ConfigProvider';
import styles from '../../../../styles/cspace-ui/SearchTable.css';
import SearchResultTableRow from './SearchResultTableRow';
import { getListTypeFromResult } from '../../../helpers/searchHelpers';
const propTypes = {
searchDescriptor: PropTypes.instanceOf(Immutable.Map),
intl: PropTypes.object,
};
const messages = defineMessages({
selectHeader: {
id: 'searchTable.selectHeaderAll',
description: 'Label for select table header',
defaultMessage: 'Selected',
},
});
function getSortDir(searchDescriptor) {
const searchQuery = searchDescriptor.get('searchQuery');
const sortSpec = searchQuery.get('sort');
let sortDir;
let sortColumnName;
if (sortSpec) {
[sortColumnName, sortDir] = sortSpec.split(' ');
if (!sortDir) {
sortDir = 'asc';
}
}
return { sortColumnName, sortDir };
}
/**
* Displays search results as a table. This uses the search descriptor to get the
* record type in order to read the configuration for what headers and fields need
* to be displayed.
*
* Once complete this should replace the older SearchResultTable component
*
* todo: parity with other search result table
* - aria-labels + general wcag compliance
* - figure out hrefs
* - ???
*/
function SearchResultTable({ searchDescriptor, intl }) {
const config = useConfig();
const results = useSelector((state) => getSearchResult(state,
SEARCH_RESULT_PAGE_SEARCH_NAME,
searchDescriptor));
const selectedItems = useSelector((state) => getSearchSelectedItems(state,
SEARCH_RESULT_PAGE_SEARCH_NAME));
const listType = getListTypeFromResult(config, results);
const {
list,
items,
} = readListItems(config, listType, results);
if (!items) {
return null;
}
// Might move this into the SearchResultTableHeader
const {
sortColumnName,
sortDir,
} = getSortDir(searchDescriptor);
// read headers
const columnConfig = getColumnConfig(config, searchDescriptor, 'default');
// todo: dataKey is for ucb support. basically it allows multiple fields to be used
// in the event one is missing. See cspace-ui-plugin-profile-pahma.js
const columns = Object.keys(columnConfig)
.filter((name) => !columnConfig[name].disabled)
.sort((nameA, nameB) => {
const orderA = columnConfig[nameA].order;
const orderB = columnConfig[nameB].order;
return orderA - orderB;
}).map((name) => {
const column = columnConfig[name];
return {
dataKey: column.dataKey || name,
formatValue: (data) => {
if (column.formatValue) {
const formatterContext = {
intl,
config,
data,
};
return column.formatValue(data, formatterContext);
}
return data;
},
label: () => {
const message = get(column, ['messages', 'label']);
return message ? intl.formatMessage(message) : '';
},
};
});
const renderContext = {
listType,
searchDescriptor,
selectedItems,
columns,
};
const totalItems = parseInt(list.get('totalItems'), 10);
const selectLabel = intl.formatMessage(messages.selectHeader);
// todo: showCheckbox prop
return (
<div className={styles.results}>
<table>
<thead>
<tr>
{/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
<th className={styles.checkbox} aria-label={selectLabel} />
{columns.map((column) => (sortColumnName === column.dataKey
? <SearchResultTableHeader key={column.dataKey} column={column} sort={sortDir} />
: <SearchResultTableHeader key={column.dataKey} column={column} />
))}
</tr>
</thead>
<tbody>
{items.map((item, index) => (
<SearchResultTableRow
key={item.get('csid')}
item={item}
index={index}
totalItems={totalItems}
renderContext={renderContext}
/>
))}
</tbody>
</table>
</div>
);
}
SearchResultTable.propTypes = propTypes;
export default injectIntl(SearchResultTable);