import { registerComponent, Components, getCollection, Utils } from 'meteor/vulcan:lib'; import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import withCurrentUser from '../containers/withCurrentUser.js'; import withMulti from '../containers/withMulti.js'; import { FormattedMessage, intlShape } from 'meteor/vulcan:i18n'; import { getFieldValue } from './Card.jsx'; /* Datatable Component */ // see: http://stackoverflow.com/questions/1909441/jquery-keyup-delay const delay = (function(){ var timer = 0; return function(callback, ms){ clearTimeout (timer); timer = setTimeout(callback, ms); }; })(); class Datatable extends PureComponent { constructor() { super(); this.updateQuery = this.updateQuery.bind(this); this.state = { value: '', query: '', currentSort: {} } } toggleSort = column => { let currentSort; if (!this.state.currentSort[column]) { currentSort = { [column] : 1 }; } else if (this.state.currentSort[column] === 1) { currentSort = { [column] : -1 }; } else { currentSort = {}; } this.setState({ currentSort }); } updateQuery(e) { e.persist() e.preventDefault(); this.setState({ value: e.target.value }); delay(() => { this.setState({ query: e.target.value }); }, 700 ); } render() { if (this.props.data) { // static JSON datatable return ; } else { // dynamic datatable with data loading const collection = this.props.collection || getCollection(this.props.collectionName); const options = { collection, ...this.props.options } const DatatableWithMulti = withMulti(options)(Components.DatatableContents); const canInsert = collection.options && collection.options.mutations && collection.options.mutations.new && collection.options.mutations.new.check(this.props.currentUser); return (
) } } } Datatable.propTypes = { title: PropTypes.string, collection: PropTypes.object, columns: PropTypes.array, data: PropTypes.array, options: PropTypes.object, showEdit: PropTypes.bool, showNew: PropTypes.bool, showSearch: PropTypes.bool, newFormOptions: PropTypes.object, editFormOptions: PropTypes.object, emptyState: PropTypes.object, } Datatable.defaultProps = { showNew: true, showEdit: true, showSearch: true, } registerComponent('Datatable', Datatable, withCurrentUser); /* DatatableAbove Component */ const DatatableAbove = (props) => { const { collection, currentUser, showSearch, showNew, canInsert, value, updateQuery, options, newFormOptions } = props; return (
{showSearch && } {showNew && canInsert && }
) } registerComponent('DatatableAbove', DatatableAbove); /* DatatableHeader Component */ const DatatableHeader = ({ collection, column, toggleSort, currentSort }, { intl }) => { const columnName = typeof column === 'string' ? column : column.label || column.name; if (collection) { const schema = collection.simpleSchema()._schema; /* use either: 1. the column name translation 2. the column name label in the schema (if the column name matches a schema field) 3. the raw column name. */ const defaultMessage = schema[columnName] ? schema[columnName].label : Utils.camelToSpaces(columnName); const formattedLabel = intl.formatMessage({ id: `${collection._name}.${columnName}`, defaultMessage }); // if sortable is a string, use it as the name of the property to sort by. If it's just `true`, use column.name const sortPropertyName = typeof column.sortable === 'string' ? column.sortable : column.name; return column.sortable ? : {formattedLabel}; } else { const formattedLabel = intl.formatMessage({ id: columnName, defaultMessage: columnName }); return {formattedLabel}; } } DatatableHeader.contextTypes = { intl: intlShape }; registerComponent('DatatableHeader', DatatableHeader); const SortNone = () => const SortDesc = () => const SortAsc = () => const DatatableSorter = ({ name, label, toggleSort, currentSort }) =>
{toggleSort(name)}}> {label} {!currentSort[name] ? ( ) : currentSort[name] === 1 ? ( ) : ( ) }
registerComponent('DatatableSorter', DatatableSorter); /* DatatableContents Component */ const DatatableContents = (props) => { // if no columns are provided, default to using keys of first array item const { title, collection, results, columns, loading, loadMore, count, totalCount, networkStatus, showEdit, currentUser, emptyState, toggleSort, currentSort } = props; if (loading) { return
; } else if (!results || !results.length) { return emptyState || null; } const isLoadingMore = networkStatus === 2; const hasMore = totalCount > results.length; return (
{title && } {_.sortBy(columns, column => column.order).map((column, index) => )} {showEdit ? : null} {results.map((document, index) => )}
{hasMore &&
{isLoadingMore ? : {e.preventDefault(); loadMore();}}>Load More ({count}/{totalCount}) }
}
) } registerComponent('DatatableContents', DatatableContents); /* DatatableTitle Component */ const DatatableTitle = ({ title }) =>
{title}
registerComponent('DatatableTitle', DatatableTitle); /* DatatableRow Component */ const DatatableRow = (props, { intl }) => { const { collection, columns, document, showEdit, currentUser, options, editFormOptions, rowClass } = props; const canEdit = collection && collection.options && collection.options.mutations && collection.options.mutations.edit && collection.options.mutations.edit.check(currentUser, document); const row = typeof rowClass === 'function' ? rowClass(document) : rowClass || ''; const modalProps = { title: {document._id} }; return ( {_.sortBy(columns, column => column.order).map((column, index) => )} {showEdit && canEdit ? : null} ) } registerComponent('DatatableRow', DatatableRow); DatatableRow.contextTypes = { intl: intlShape }; /* DatatableCell Component */ const DatatableCell = ({ column, document, currentUser }) => { const Component = column.component || column.componentName && Components[column.componentName] || Components.DatatableDefaultCell; const columnName = column.name || column; return ( ) } registerComponent('DatatableCell', DatatableCell); /* DatatableDefaultCell Component */ const DatatableDefaultCell = ({ column, document }) =>
{typeof column === 'string' ? getFieldValue(document[column]) : getFieldValue(document[column.name])}
registerComponent('DatatableDefaultCell', DatatableDefaultCell);