UNPKG

periodicjs.ext.reactapp

Version:
348 lines (338 loc) 12.3 kB
import React, { Component, PropTypes, } from 'react'; import { Link, } from 'react-router'; // import flatten from 'flat'; import qs from 'querystring'; import * as rb from 're-bulma'; import debounce from 'debounce'; import utilities from '../../util'; import pluralize from 'pluralize'; const propTypes = { returnProperty: PropTypes.any, //false or string property value disabled: PropTypes.bool, returnFormOptionsValue: PropTypes.bool, selector: PropTypes.string, displayfield: PropTypes.string, displayProps: PropTypes.object, dbname: PropTypes.string, multi: PropTypes.bool, createable: PropTypes.bool, flattenDataList: PropTypes.bool, flattenDataListOptions: PropTypes.any, selectedData: PropTypes.any, resourceUrl: PropTypes.string, createResourceUrl: PropTypes.string, data: PropTypes.array, value: PropTypes.any, onChange: PropTypes.func, onFocus: PropTypes.func, onBlur: PropTypes.func, limit: PropTypes.number, datalistdata: PropTypes.array, }; const defaultProps = { disabled: false, returnProperty: false, returnFormOptionsValue: false, data: false, createable: false, value: undefined, displayProps: {}, selectData: [], flattenDataList: true, flattenDataListOptions: {}, selector: '_id', displayField: 'title', dbname: 'periodic', limit: 10, datalistdata: [], onChange: (data) => { console.debug('ResponsiveDatalist onChange', { data, }); }, onFocus: (data) => { console.debug('ResponsiveDatalist onFocus', { data, }); }, onBlur: (data) => { console.debug('ResponsiveDatalist onBlur', { data, }); }, }; function getDatumValue(datum) { // eslint-disable-next-line let returnProperty = (this.props.returnFormOptionsValue || datum && typeof datum ==='object' && (Object.keys(datum).length === 2 && typeof datum.label !== 'undefined' && typeof datum.value !== 'undefined')) ? 'value' : this.props.returnProperty; // if (typeof this.props.returnProperty !== 'string') returnProperty = this.props.selector; // if(typeof datum !== 'object') console.error('datum is not an object') return (returnProperty && typeof datum === 'object') ? datum[ returnProperty ] : datum; } class ResponsiveDatalist extends Component { constructor(props) { super(props); // console.log('ResponsiveDatalist',{ props }); let initialValue = props.value; if (props.multi && props.value && Array.isArray(props.value) === false && props.value.indexOf(',') >= 0) { initialValue = props.value.split(','); } this.state = { disabled: props.disabled, data: props.data, value: (props.multi && initialValue && Array.isArray(initialValue) === false) ? [initialValue, ] : initialValue, internal_value: (props.multi && initialValue && Array.isArray(initialValue) === false) ? [initialValue, ] : initialValue, selectedData: props.selectedData, isSearching: false, }; // console.warn('ResponsiveDatalist this.state',this.state); this.inputProps = Object.assign({}, this.props.passableProps); this.searchFunction = debounce(this.updateDataList, 200); this.filterStaticData = this.filterStaticData.bind(this); this.getDatum = getDatumValue.bind(this); this.updateDataList = this.updateDataList.bind(this); } componentWillReceiveProps(nextProps) { // console.debug({ nextProps }); // this.setState(Object.assign({}, nextProps, this.props.getState())); // // console.log('this.state', this.state); } filterStaticData(options) { // console.warn('this.props.datalistdata',this.props.datalistdata) if (this.props.returnFormOptionsValue) { return this.props.datalistdata.filter(item => (item.label.indexOf(options.search) > -1)); } else if (options.search) { return this.props.datalistdata.filter(item => (item[ this.props.field ].indexOf(options.search) > -1)); } else { return this.props.datalistdata; } } updateDataList(options) { // console.log('this.props.resourceUrl', this.props.resourceUrl); if (this.props.resourceUrl) { this.setState({ isSearching: true, }); let stateProps = this.props.getState(); let fetchURL = `${this.props.resourceUrl}&${qs.stringify({ limit: this.props.limit, // sort: (newSortOptions.sortProp) // ? `${newSortOptions.sortOrder}${newSortOptions.sortProp}` // : undefined, query: options.search, allowSpecialCharacters: true, // pagenum: options.pagenum || 1, })}`; let headers = Object.assign({ 'x-access-token': stateProps.user.jwt_token, }, stateProps.settings.userprofile.options.headers); utilities.fetchComponent(fetchURL, { headers, })() .then(response => { if (response.data && response.result && response.status) { response = response.data; } // console.debug('this.state.value',this.state.value); let updatedState = {}; updatedState.selectedData = response[pluralize(this.props.entity)]; updatedState.isSearching = false; this.setState(updatedState); }, e => { this.props.errorNotification(e); }); } else if (this.props.staticSearch) { this.setState({ isSearching: true, }); //options.search is the actual content let updatedState = {}; updatedState.selectedData = this.filterStaticData(options); updatedState.isSearching = false; // console.debug({updatedState,response}); this.setState(updatedState); //value is the array of selected values //selectedData is the filtered list that changes everytime user types // console.warn({ options, }); } else{ console.debug({ options, }); } } onChangeHandler(event) { console.warn('onChangeHandler', { event }); const search = (event && event.target && event.target.value) ? event.target.value : ''; console.warn('onChangeHandler', { search }); this.searchFunction({ search, }); } onBlurHandler() { setTimeout(() => { this.setState({ selectedData: [], }); }, 400); } getDatalistDisplay(options){ let { displayField, selector, datum, } = options; let displayText = datum[ displayField ] || datum.title || datum.name || datum.username || datum.email || datum[ selector ] || ((datum && typeof datum === 'string') ? datum : ''); // console.debug('getDatalistDisplay', { options,displayText }); return (<span style={{ wordBreak: 'break-all', textOverflow: 'ellipsis', overflow: 'hidden', whiteSpace: 'pre-wrap', wordWrap: 'break-word', }}> { (datum && datum.fileurl && datum.transform && datum.transform.preview) ?<rb.Image src={datum.transform.preview} size="is24X24" style={{ float:'left', marginRight:'5px', }}/> :null } { (this.props.resourcePreview) ? <Link title={datum.title||displayText} to={`${this.props.resourcePreview}/${datum[selector]||datum}`}>{displayText}</Link> : displayText } { (this.props.resourceDescription) ? <rb.Content><p>{datum.description}</p></rb.Content> : null } </span>); } removeDatalistItem(index) { // console.debug('clicked datalist',{index}); // console.debug('clicked onclick',this.props); // console.debug('this.state.value',this.state.value); if (this.props.multi) { let newValue = [].concat(this.state.internal_value); newValue.splice(index, 1); // let oldValue = this.state.value; this.setState({ value:newValue.map(v=>this.getDatum(v)), internal_value:newValue, selectedData: [], update: new Date(), }, () => { // this.props.onChange([]); this.props.onChange(newValue.map(v=>this.getDatum(v))); }); } else { let datum = undefined; this.setState({ value:this.getDatum(datum), internal_value:datum, selectedData: [], }, () => { this.props.onChange(datum); }); } } render() { let notificationStyle={ marginBottom: '5px', padding:'5px', border:'1px solid lightgrey', }; let notificationCloseStyle={ margin: '0px 0px 0px 20px', borderRadius: '19px', }; let selectData = (this.props.multi) ? (this.state.internal_value && this.state.internal_value.length ) ? (this.state.internal_value.map((selected, k)=>{ return (<rb.Notification key={k} enableCloseButton closeButtonProps={{ onClick: this.removeDatalistItem.bind(this, k), style: notificationCloseStyle, }} style={notificationStyle} > {this.getDatalistDisplay({ // datum:selected, datum:this.state.internal_value[k], displayField: this.props.displayField, selector: this.props.selector, })} </rb.Notification>); })) : null : (this.state.value) ?(<rb.Notification enableCloseButton closeButtonProps={{ onClick: this.removeDatalistItem.bind(this), style: notificationCloseStyle, }} style={notificationStyle} > {this.getDatalistDisplay({ // datum:this.state.value, datum:this.state.internal_value, displayField: this.props.displayField, selector: this.props.selector, })} </rb.Notification>) : null; let displayOptions = (Array.isArray(this.state.selectedData) && this.state.selectedData && this.state.selectedData.length) ? this.state.selectedData.map((datum, k) => { return ( <rb.Notification key={k} color="isWhite" style={notificationStyle} > <rb.Button icon="fa fa-plus" size="isSmall" style={{ alignSelf:'flex-end', borderRadius:'20px', float: 'right', paddingRight: '0px', }} onClick={()=>{ if(this.props.multi){ let newValue = (this.state.internal_value && Array.isArray(this.state.internal_value) && this.state.internal_value.length) ? this.state.internal_value.concat([(datum), ]) : [(datum), ]; this.setState({ value:newValue.map(v=>this.getDatum(v)), internal_value:newValue, selectedData: [], }, () => { this.props.onChange(newValue.map(v=>this.getDatum(v))); }); } else { this.setState({ value: this.getDatum(datum), // datum, internal_value: datum, // datum, selectedData: [], }, () => { this.props.onChange(datum); }); } }}/> {this.getDatalistDisplay({ datum, displayField: this.props.displayField, selector: this.props.selector, })} </rb.Notification>); }) : null; // console.log('this.inputProps',this.inputProps) return(<div {...this.props.wrapperProps}> <div style={{ width:'100%', }}> <rb.Input {...this.inputProps} state={this.state.isSearching || undefined} onChange={this.onChangeHandler.bind(this)} onBlur={this.onBlurHandler.bind(this)} onFocus={this.onChangeHandler.bind(this)} ref={(input)=>{ this.textInput = input; }} /> </div> <div {...this.props.displayProps}> { displayOptions }</div> <div>{ selectData }</div> </div>); } } ResponsiveDatalist.propType = propTypes; ResponsiveDatalist.defaultProps = defaultProps; export default ResponsiveDatalist;