/* * * List * */ import React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators, compose } from 'redux'; import { createStructuredSelector } from 'reselect'; import PropTypes from 'prop-types'; import { isEmpty, isUndefined, map, get, toInteger } from 'lodash'; import { router } from 'app'; // Selectors. import { makeSelectModels, makeSelectSchema } from 'containers/App/selectors'; // Components. import Table from 'components/Table'; import TableFooter from 'components/TableFooter'; import PluginHeader from 'components/PluginHeader'; import PopUpWarning from 'components/PopUpWarning'; import injectReducer from 'utils/injectReducer'; import injectSaga from 'utils/injectSaga'; // Utils import getQueryParameters from 'utils/getQueryParameters'; // Actions. import { deleteRecord, } from '../Edit/actions'; // Styles. import styles from './styles.scss'; // Actions. import { setCurrentModelName, loadRecords, loadCount, changePage, changeSort, changeLimit, } from './actions'; // Selectors. import { makeSelectRecords, makeSelectCurrentModelName, makeSelectCurrentModelNamePluralized, makeSelectCount, makeSelectCurrentPage, makeSelectLimit, makeSelectSort, makeSelectLoadingCount, } from './selectors'; import reducer from './reducer'; import saga from './sagas'; export class List extends React.Component { constructor(props) { super(props); this.state = { showWarning: false, source: getQueryParameters(props.location.search, 'source'), }; } componentDidMount() { // Init the view this.init(this.props); } componentWillReceiveProps(nextProps) { const locationChanged = nextProps.location.pathname !== this.props.location.pathname; if (locationChanged) { this.init(nextProps); } if (!isEmpty(nextProps.location.search) && this.props.location.search !== nextProps.location.search) { this.props.loadRecords(this.state.source); } } init(props) { const slug = props.match.params.slug; // Set current model name this.props.setCurrentModelName(slug.toLowerCase()); const sort = (isEmpty(props.location.search) ? get(this.props.models, ['models', slug.toLowerCase(), 'primaryKey']) || get(this.props.models.plugins, [this.state.source, 'models', slug.toLowerCase(), 'primaryKey']) : getQueryParameters('sort')) || 'id'; if (!isEmpty(props.location.search)) { this.props.changePage(toInteger(getQueryParameters('page')), this.state.source); this.props.changeLimit(toInteger(getQueryParameters('limit')), this.state.source); } this.props.changeSort(sort, this.state.source); // Load records this.props.loadRecords(this.state.source); // Get the records count this.props.loadCount(this.state.source); // Define the `create` route url this.addRoute = `${this.props.match.path.replace(':slug', slug)}/create`; } handleChangeLimit = ({ target }) => { this.props.changeLimit(toInteger(target.value), this.state.source); router.push({ pathname: this.props.location.pathname, search: `?page=${this.props.currentPage}&limit=${target.value}&sort=${this.props.sort}&source=${this.state.source}`, }); } handleChangePage = (page) => { router.push({ pathname: this.props.location.pathname, search: `?page=${page}&limit=${this.props.limit}&sort=${this.props.sort}&source=${this.state.source}`, }); this.props.changePage(page, this.state.source); } handleChangeSort = (sort) => { router.push({ pathname: this.props.location.pathname, search: `?page=${this.props.currentPage}&limit=${this.props.limit}&sort=${sort}&source=${this.state.source}`, }); this.props.changeSort(sort, this.state.source); } handleDelete = (e) => { e.preventDefault(); e.stopPropagation(); this.props.deleteRecord(this.state.target, this.props.currentModelName, this.state.source); this.setState({ showWarning: false }); } toggleModalWarning = (e) => { if (!isUndefined(e)) { e.preventDefault(); e.stopPropagation(); this.setState({ target: e.target.id, }); } this.setState({ showWarning: !this.state.showWarning }); } render() { // Detect current model structure from models list const currentModel = get(this.props.models, ['models', this.props.currentModelName]) || get(this.props.models, ['plugins', this.state.source, 'models', this.props.currentModelName]); const currentSchema = get(this.props.schema, [this.props.currentModelName]) || get(this.props.schema, ['plugins', this.state.source, this.props.currentModelName]); if (!this.props.currentModelName || !currentSchema) { return
; } // Define table headers const tableHeaders = map(currentSchema.list, (value) => ({ name: value, label: currentSchema.fields[value].label, type: currentSchema.fields[value].type, })); tableHeaders.splice(0, 0, { name: currentModel.primaryKey || 'id', label: 'Id', type: 'string' }); const content = ( ); // Plugin header config const pluginHeaderTitle = currentSchema.label || 'Content Manager'; // Define plugin header actions const pluginHeaderActions = [ { label: 'content-manager.containers.List.addAnEntry', labelValues: { entity: pluginHeaderTitle, }, kind: 'primaryAddShape', onClick: () => this.context.router.history.push({ pathname: this.addRoute, search: `?source=${this.state.source}`, }), }, ]; return (
{content}
); } } List.contextTypes = { router: PropTypes.object.isRequired, }; List.propTypes = { changeLimit: PropTypes.func.isRequired, changePage: PropTypes.func.isRequired, changeSort: PropTypes.func.isRequired, count: PropTypes.oneOfType([ PropTypes.number, PropTypes.bool, ]).isRequired, currentModelName: PropTypes.oneOfType([ PropTypes.string, PropTypes.bool, ]).isRequired, currentPage: PropTypes.number.isRequired, deleteRecord: PropTypes.func.isRequired, history: PropTypes.object.isRequired, limit: PropTypes.number.isRequired, loadCount: PropTypes.func.isRequired, loadRecords: PropTypes.func.isRequired, location: PropTypes.object.isRequired, match: PropTypes.object.isRequired, models: PropTypes.oneOfType([ PropTypes.object, PropTypes.bool, ]).isRequired, records: PropTypes.oneOfType([ PropTypes.array, PropTypes.object, ]).isRequired, // route: PropTypes.object.isRequired, schema: PropTypes.oneOfType([ PropTypes.bool, PropTypes.object, ]).isRequired, setCurrentModelName: PropTypes.func.isRequired, sort: PropTypes.string.isRequired, }; function mapDispatchToProps(dispatch) { return bindActionCreators( { deleteRecord, setCurrentModelName, loadRecords, loadCount, changePage, changeSort, changeLimit, }, dispatch ); } const mapStateToProps = createStructuredSelector({ records: makeSelectRecords(), count: makeSelectCount(), loadingCount: makeSelectLoadingCount(), models: makeSelectModels(), currentPage: makeSelectCurrentPage(), limit: makeSelectLimit(), sort: makeSelectSort(), currentModelName: makeSelectCurrentModelName(), currentModelNamePluralized: makeSelectCurrentModelNamePluralized(), schema: makeSelectSchema(), }); const withConnect = connect(mapStateToProps, mapDispatchToProps); const withReducer = injectReducer({ key: 'list', reducer }); const withSaga = injectSaga({ key: 'list', saga }); export default compose( withReducer, withSaga, withConnect, )(List);