Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * Created by michal.mielczynski@w-b.pl on 2017-06-13.
- */
- import React, {Component} from 'react';
- import {autobind} from 'core-decorators';
- import {
- Panel,
- FormGroup,
- FormControl,
- HelpBlock,
- Button,
- ButtonGroup,
- OverlayTrigger,
- Tooltip,
- Well,
- Row,
- Col,
- Glyphicon,
- Badge,
- PanelGroup,
- Modal
- } from 'react-bootstrap';
- import Select from 'react-select';
- import Spinner from 'react-spinner';
- import Alert from 'react-s-alert';
- import TrackerReact from 'meteor/ultimatejs:tracker-react';
- import i18n from 'meteor/universe:i18n';
- import {Customers, Concerns, Trades, Countries} from '/imports/lib/collections/collections-general';
- import {CustomerList} from './customer-list';
- import {isElementVisible} from '/imports/client/utils/util-is-element-visible';
- import {userNameFromId} from '/imports/lib/utils/util-username-from-id';
- import _ from 'lodash';
- const T = i18n.createComponent();
- const clearSearchFiltersToolTip = <Tooltip id={'1'}><T>tooltip.clearSearch</T></Tooltip>;
- const addFilterTooltip = <Tooltip id={'2'}><T>tooltip.addFilter</T></Tooltip>;
- const myCustomersTooltip = <Tooltip id={'5'}><T>tooltip.myCustomers</T></Tooltip>;
- const ITEMS_PER_PAGE = Meteor.settings.public.customersPerPage || 10;
- const CUSTOMER_SORTING = Meteor.settings.public.sortingOptionsCustomer || {
- name: 1
- };
- const MAX_PAGES = Meteor.settings.public.customersMaxPages || 20;
- const MAX_FILTER_NAME = Meteor.settings.public.maxFilterName || 10;
- @autobind
- export class CustomerListWrapper extends TrackerReact(Component) {
- constructor(props) {
- super(props);
- let customerFilter = {};
- if (Session.get('customerFilter')) {
- customerFilter = JSON.parse(Session.get('customerFilter'));
- }
- let nameFilterValue = '';
- if (Session.get('customerNameFilterValue')) {
- nameFilterValue = JSON.parse(Session.get('customerNameFilterValue'));
- }
- let ownerFilterValue = '';
- if (Session.get('customerOwnerFilterValue')) {
- ownerFilterValue = JSON.parse(Session.get('customerOwnerFilterValue'));
- }
- let concernsValue = [];
- if (Session.get('customerConcernFilterValue')) {
- concernsValue = JSON.parse(Session.get('customerConcernFilterValue'));
- }
- let tradesValue = [];
- if (Session.get('customerTradeFilterValue')) {
- tradesValue = JSON.parse(Session.get('customerTradeFilterValue'));
- }
- let countriesValue = [];
- if (Session.get('customerCountriesFilterValue')) {
- countriesValue = JSON.parse(Session.get('customerCountriesFilterValue'));
- }
- this.state = {
- collectionsLoaded: false,
- globalCustomerCount: 0,
- pageCount: 1,
- customerFilter,
- nameFilterValue,
- ownerFilterValue,
- concernsValue,
- tradesValue,
- countriesValue,
- bottomText: '',
- filterNameModal: false,
- filterRenameId: '',
- filterRemoveModal: false,
- filterRemoveId: '',
- newFilterName: ''
- };
- this.subscriptions = {
- customers: Meteor.subscribe('customers', this.subscriptionsUpdated),
- users: Meteor.subscribe('user-names', this.subscriptionsUpdated),
- countries: Meteor.subscribe('countries', this.subscriptionsUpdated),
- trades: Meteor.subscribe('trades', this.subscriptionsUpdated),
- concerns: Meteor.subscribe('concerns', this.subscriptionsUpdated)
- };
- }
- componentDidMount() {
- window.addEventListener('scroll', this.handleScrollEnd, false);
- this.checkCustomerCount();
- }
- componentWillUnmount() {
- this.subscriptions.customers.stop();
- this.subscriptions.users.stop();
- this.subscriptions.countries.stop();
- this.subscriptions.trades.stop();
- this.subscriptions.concerns.stop();
- Session.set('customerFilter', JSON.stringify(this.state.customerFilter));
- Session.set('customerNameFilterValue', JSON.stringify(this.state.nameFilterValue));
- Session.set('customerOwnerFilterValue', JSON.stringify(this.state.ownerFilterValue));
- Session.set('customerCountriesFilterValue', JSON.stringify(this.state.countriesValue));
- Session.set('customerTradeFilterValue', JSON.stringify(this.state.tradesValue));
- Session.set('customerConcernFilterValue', JSON.stringify(this.state.concernsValue));
- window.removeEventListener('scroll', this.handleScrollEnd);
- }
- handleScrollEnd() {
- this.container = document.getElementById('feed');
- if (this.container) {
- if (isElementVisible(this.container)) {
- this.loadMore();
- }
- }
- else {
- console.log('no container');
- }
- }
- loadMore() {
- if (!this.listContainer) {
- return
- }
- let cC = Customers.find(this.state.customerFilter).count();
- if (this.state.globalCustomerCount > cC) {
- this.setState({bottomText: i18n.__('word.loading')});
- }
- else {
- this.setState({bottomText: i18n.__('word.noMoreMatches')});
- return;
- }
- if (this.state.pageCount >= MAX_PAGES) {
- this.setState({bottomText: i18n.__('word.narrowDownCriteria')});
- }
- else if (this.state.collectionsLoaded) {
- let pageCount = this.state.pageCount + 1;
- this.setState({pageCount});
- this.subscribeCustomers();
- }
- }
- subscribeCustomers() {
- this.subscriptions.customers = Meteor.subscribe('customers', this.state.customerFilter, {
- limit: ITEMS_PER_PAGE * this.state.pageCount,
- sort: CUSTOMER_SORTING
- }, this.subscriptionsUpdated);
- }
- customers() {
- return Customers.find(this.state.customerFilter, {
- limit: ITEMS_PER_PAGE * this.state.pageCount,
- sort: CUSTOMER_SORTING
- }).fetch();
- }
- countries() {
- return Countries.find().fetch().map(country => {
- country.name = i18n.__('countryNames.' + country.name);
- return country;
- });
- }
- trades() {
- return Trades.find().fetch();
- }
- concerns() {
- return Concerns.find().fetch();
- }
- options(collection) {
- const options = [];
- (collection.map((item) => {
- options.push({label: item.name, value: item._id});
- }));
- return options;
- }
- /**
- * check how many matching products are on remote database (might be more than in local minimongo)
- */
- checkCustomerCount() {
- Meteor.call('customers.count', this.state.customerFilter, (err, count) => {
- if (!err) {
- this.setState({globalCustomerCount: count});
- this.subscribeCustomers();
- }
- })
- }
- handleSelectChange(key, values) {
- switch (key) {
- case 'country':
- this.setState({countriesValue: values});
- break;
- case 'trade':
- this.setState({tradesValue: values});
- break;
- case 'concern':
- this.setState({concernsValue: values});
- break;
- default:
- console.error('undefined key', key);
- break;
- }
- let filter = this.state.customerFilter;
- delete filter[key];
- if (values instanceof Array && values.length) {
- let labels = [];
- for (let i = 0; i < values.length; i++) {
- labels.push(values[i].value);
- }
- filter[key] = {$in: labels};
- }
- this.setState({
- customerFilter: filter,
- bottomText: ''
- });
- this.checkCustomerCount();
- }
- handleNameFilterChange(e) {
- let value = '';
- if (e.target === undefined) {
- value = e;
- } else {
- value = e.target.value;
- }
- let filter = this.state.customerFilter;
- if (value) {
- filter.name = {$regex: value}
- }
- else {
- delete filter.name;
- }
- this.setState({
- nameFilterValue: value,
- customerFilter: filter,
- pageCount: 1,
- bottomText: ''
- });
- this.checkCustomerCount();
- }
- handleOwnerFilterChange(ownerFilterValue) {
- this.setState({
- ownerFilterValue: ownerFilterValue
- });
- Meteor.call('user.ids', ownerFilterValue, (err, result) => {
- if (err) {
- throw new Meteor.Error(err);
- }
- let filter = this.state.customerFilter;
- if (ownerFilterValue && ownerFilterValue.length) {
- filter.owner = {$in: result};
- }
- else {
- delete filter.owner;
- }
- this.setState({
- ownerFilterValue: ownerFilterValue,
- customerFilter: filter
- });
- });
- this.checkCustomerCount();
- }
- subscriptionsUpdated() {
- this.setState({
- collectionsLoaded: (
- this.subscriptions.customers.ready()
- && this.subscriptions.users.ready()
- && this.subscriptions.countries.ready()
- && this.subscriptions.trades.ready()
- && this.subscriptions.concerns.ready()
- )
- });
- }
- buttonsCustomFilter() {
- return (
- <ButtonGroup className='filter-button-group' justified>
- <OverlayTrigger overlay={clearSearchFiltersToolTip} placement='bottom'>
- <ButtonGroup>
- <Button
- onClick={this.clearSearch}
- >
- <Glyphicon glyph='remove'/>
- </Button>
- </ButtonGroup>
- </OverlayTrigger>
- <OverlayTrigger overlay={myCustomersTooltip} placement='bottom'>
- <ButtonGroup>
- <Button
- disabled={!Meteor.userId()}
- onClick={this.handleOwnerFilterChange.bind(this, userNameFromId(Meteor.userId()))}
- >
- <Glyphicon glyph='user'/>
- </Button>
- </ButtonGroup>
- </OverlayTrigger>
- <OverlayTrigger overlay={addFilterTooltip} placement='bottom'>
- <ButtonGroup>
- <Button
- disabled={!Meteor.userId() || _.isEmpty(this.state.customerFilter)}
- onClick={this.saveCustomFilter}
- >
- <Glyphicon glyph='plus-sign'/>
- </Button>
- </ButtonGroup>
- </OverlayTrigger>
- </ButtonGroup>
- )
- }
- saveCustomFilter() {
- if (_.isEmpty(this.state.customerFilter)) {
- Alert.error(i18n.__('alerts.filterEmpty'));
- return
- }
- let country = this.state.countriesValue;
- if (_.isEmpty(country)) {
- country = []
- }
- let trade = this.state.tradesValue;
- if (_.isEmpty(trade)) {
- trade = []
- }
- let concern = this.state.concernsValue;
- if (_.isEmpty(concern)) {
- concern = []
- }
- let options = {
- 'owner': this.state.ownerFilterValue,
- 'name': this.state.nameFilterValue,
- 'concern': concern,
- 'trade': trade,
- 'country': country
- };
- if (_.has(Meteor.user(), 'filters')) {
- let userFilters = Meteor.user().filters.customer;
- for (let key in userFilters) {
- let toCompare = userFilters[key].options;
- delete toCompare.filterName;
- if (_.isEqual(toCompare, options)) {
- return Alert.error(i18n.__('alerts.filterExists'));
- }
- }
- }
- Meteor.call('user-add-filter', Meteor.userId(), 'customer', options, (err) => {
- if (err) {
- Alert.error(i18n.__(err.reason, err.details));
- } else {
- Alert.success(i18n.__('alerts.filterAdded'));
- }
- });
- }
- removeCustomFilter() {
- this.setState({
- filterRemoveModal: false
- });
- if (!Meteor.userId()) {
- Alert.error(i18n.__('alerts.filterLogIn'));
- return
- }
- Meteor.call('user-remove-filter', Meteor.userId(), 'customer', this.state.filterRemoveId, (err) => {
- if (err) {
- Alert.error(i18n.__(err.reason, err.details));
- } else {
- Alert.success(i18n.__('alerts.filterRemoved'));
- }
- });
- };
- useCustomFilter(options) {
- this.handleNameFilterChange(options.name);
- this.handleOwnerFilterChange(options.owner);
- this.handleSelectChange('country', options.country);
- this.handleSelectChange('trade', options.trade);
- this.handleSelectChange('concern', options.concern);
- }
- setNewFilterName(filterId, newName) {
- this.setState({
- filterNameModal: false,
- newFilterName: ''
- });
- Meteor.call('user-edit-filter', Meteor.userId(), 'customer', filterId, newName, (err) => {
- if (err) {
- Alert.error(i18n.__(err.reason, err.details));
- } else {
- Alert.success(i18n.__('alerts.filterUpdated'));
- }
- })
- }
- showDeleteModal() {
- return (
- <Modal show={this.state.filterRemoveModal} onHide={() => this.setState({filterRemoveModal: false})}>
- <Modal.Header closeButton>
- <Modal.Title><T>filters.modalRemove.title</T></Modal.Title>
- </Modal.Header>
- <Modal.Body>
- <p>
- <T>filters.modalRemove.confirm</T>
- </p>
- </Modal.Body>
- <Modal.Footer>
- <Button
- bsStyle='danger'
- onClick={this.removeCustomFilter.bind(this)}
- >
- <T>word.remove</T>
- </Button>
- <Button
- onClick={() => this.setState({filterRemoveModal: false})}
- >
- <T>word.cancel</T>
- </Button>
- </Modal.Footer>
- </Modal>
- )
- }
- editFilterNameModal() {
- const hideDialog = () => {
- this.setState({
- filterNameModal: false,
- newFilterName: ''
- })
- };
- return (
- <Modal show={this.state.filterNameModal} onHide={hideDialog}>
- <Modal.Header closeButton>
- <Modal.Title><T>filters.modalEdit.title</T></Modal.Title>
- </Modal.Header>
- <Modal.Body>
- <p>
- <T>filters.modalEdit.confirm</T>
- </p>
- <FormGroup
- controlId='renameFilter'
- validationState={this.state.newFilterName.length > 10 ? 'warning' : 'success'}
- >
- <T _translateProps={['placeholder']}>
- <FormControl
- type='text'
- placeholder='filters.updateFilterName'
- value={this.state.newFilterName}
- onChange={(e) => this.setState({newFilterName: e.target.value})}
- />
- </T>
- <HelpBlock>
- {this.state.newFilterName.length > 10 ?
- <T maxLength={MAX_FILTER_NAME}>filters.customFilters.nameToLong</T> :
- <T maxLength={MAX_FILTER_NAME}>filters.customFilters.nameOk</T>
- }
- </HelpBlock>
- </FormGroup>
- </Modal.Body>
- <Modal.Footer>
- <Button
- disabled={!this.state.newFilterName || this.state.newFilterName.length > 10}
- bsStyle='primary'
- onClick={this.setNewFilterName.bind(this, this.state.filterRenameId, this.state.newFilterName)}
- >
- <T>word.save</T>
- </Button>
- <Button onClick={hideDialog}>
- <T>word.cancel</T>
- </Button>
- </Modal.Footer>
- </Modal>
- )
- }
- customFilterComponent() {
- if (!Meteor.userId()) {
- return
- }
- let user = Meteor.users.findOne(Meteor.userId());
- if (!_.has(user, 'filters') || _.isEmpty(user.filters.customer)) {
- return
- }
- let userFilters = Object.values(user.filters.customer);
- return userFilters.map((filter) => {
- let headerFilter = (
- <span className="custom-panel-header">
- {/*<OverlayTrigger overlay={useFilterTooltip} placement='top'>*/}
- <Button
- bsStyle='link'
- className="pull-left"
- bsSize='small'
- onClick={this.useCustomFilter.bind(this, filter.options)}
- >
- <Glyphicon className='custom-panel-btn' glyph='play'/>
- </Button>
- {/*</OverlayTrigger>*/}
- {filter.options.filterName}
- <ButtonGroup className="pull-right">
- {/*<OverlayTrigger overlay={expandFilterTooltip} placement='top'>*/}
- <Button
- bsStyle='link'
- className='custom-panel-btn'
- bsSize='small'
- >
- <Glyphicon glyph='chevron-down'/>
- </Button>
- {/*</OverlayTrigger>*/}
- {/*<OverlayTrigger overlay={editNameTooltip} placement='top'>*/}
- <Button
- bsStyle='link'
- bsSize='small'
- className='custom-panel-btn'
- onClick={() => {
- if (filter.options.filterName !== 'Unnamed') {
- this.setState({
- newFilterName: filter.options.filterName
- })
- }
- this.setState({
- filterNameModal: true,
- filterRenameId: _.findKey(user.filters.customer, filter)
- })
- }}
- >
- <Glyphicon glyph='edit'/>
- </Button>
- {/*</OverlayTrigger>*/}
- {/*<OverlayTrigger overlay={removeFilterTooltip} placement='left'>*/}
- <Button
- bsStyle='link'
- bsSize='small'
- className='custom-panel-btn'
- onClick={() => {
- this.setState({
- filterRemoveModal: true,
- filterRemoveId: _.findKey(user.filters.customer, filter)
- })
- }}
- >
- <Glyphicon glyph='trash'/>
- </Button>
- {/*</OverlayTrigger>*/}
- </ButtonGroup>
- </span>
- );
- const displayElement = (el, translation) => {
- if (!el || !el.length) {
- return;
- }
- if (typeof el === "string") {
- return (
- <div>
- <strong>{i18n.__('filters.customFilters.' + [translation])}</strong><br/>
- {el}
- </div>
- )
- }
- else {
- return (
- <div>
- <strong>{i18n.__('filters.customFilters.' + [translation])}</strong><br/>
- {el.map((i) => {
- return i.label + ' ';
- })}
- </div>
- )
- }
- };
- return (
- <Panel
- key={filter._id}
- header={headerFilter}
- eventKey={filter}
- className='text-center custom-panel'
- >
- <Row>
- <Col sm={12}>
- {displayElement(filter.options.name, 'name')}
- {displayElement(filter.options.owner, 'owner')}
- {displayElement(filter.options.country, 'country')}
- {displayElement(filter.options.concern, 'concern')}
- {displayElement(filter.options.trade, 'trade')}
- </Col>
- </Row>
- </Panel>
- )
- });
- };
- clearSearch() {
- this.setState(
- {
- customerFilter: {},
- nameFilterValue: '',
- ownerFilterValue: '',
- concernsValue: '',
- tradesValue: '',
- countriesValue: '',
- bottomText: ''
- },
- () => {
- this.checkCustomerCount()
- }
- );
- }
- filterPanel() {
- let header = (
- <div className='text-center'>
- <Glyphicon glyph='filter'
- className={_.isEmpty(this.state.customerFilter) ? '' : 'active-filter-glyph'}/>
- <br/>
- <Badge
- className={_.isEmpty(this.state.customerFilter) ? '' : 'active-filter-badge'}>{this.state.globalCustomerCount}</Badge>
- </div>
- );
- return (
- <Panel className='filter-panel customers-filter'
- header={header}
- expanded={true}
- >
- <T _translateProps={['placeholder']}>
- <FormControl
- type='text'
- placeholder='filters.name'
- value={this.state.nameFilterValue}
- onChange={this.handleNameFilterChange.bind(this)}
- />
- </T>
- <T _translateProps={['placeholder']}>
- <FormControl
- type='text'
- placeholder='filters.owner'
- value={this.state.ownerFilterValue}
- onChange={e => {
- this.handleOwnerFilterChange(e.target.value)
- }}
- />
- </T>
- <T _translateProps={['placeholder']}>
- <Select
- placeholder='filters.allCountries'
- value={this.state.countriesValue}
- options={this.options(this.countries())}
- multi
- onChange={this.handleSelectChange.bind(this, 'country')}
- />
- </T>
- <T _translateProps={['placeholder']}>
- <Select
- placeholder='filters.allConcerns'
- value={this.state.concernsValue}
- options={this.options(this.concerns())}
- multi
- onChange={this.handleSelectChange.bind(this, 'concern')}
- />
- </T>
- <T _translateProps={['placeholder']}>
- <Select
- placeholder='filters.allTrades'
- value={this.state.tradesValue}
- options={this.options(this.trades())}
- multi
- onChange={this.handleSelectChange.bind(this, 'trade')}
- />
- </T>
- <ButtonGroup vertical block>
- <Button
- block
- bsStyle='info'
- href='/new_customer'
- disabled={!Meteor.userId()}
- >
- <T>componentCustomer.new</T>
- </Button>
- </ButtonGroup>
- {this.buttonsCustomFilter()}
- <div className='scrollable'>
- <PanelGroup accordion>
- {this.customFilterComponent()}
- </PanelGroup>
- </div>
- </Panel>
- );
- }
- render() {
- if (!this.state.collectionsLoaded) {
- return <Spinner/>;
- }
- return (
- <div>
- {this.filterPanel()}
- {this.editFilterNameModal()}
- {this.showDeleteModal()}
- <CustomerList
- customers={this.customers()}
- ref={(ref) => this.listContainer = ref}
- />
- <div id='feed'>
- <Well>
- <div className='text-center'>
- {this.state.bottomText}
- </div>
- </Well>
- </div>
- </div>
- )
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement