diff --git a/src/containers/BGroup/BGroup.js b/src/containers/BGroup/BGroup.js index 211dbeee6984edb6871566d4a546501cb4909f6c..ac3060f9d2c11d347283da1cb3ae7ee2efb295a3 100644 --- a/src/containers/BGroup/BGroup.js +++ b/src/containers/BGroup/BGroup.js @@ -3,12 +3,12 @@ import { connect } from 'react-redux'; import { Link, browserHistory } from 'react-router'; import { bindActionCreators } from 'redux'; import PropTypes from 'prop-types'; -import { Button, Nav, NavItem, NavLink } from 'reactstrap'; -import ReactTable from 'react-table'; +import { + Button, Nav, NavItem, NavLink, +} from 'reactstrap'; import 'react-table/react-table.css'; import { Icon } from 'react-fa'; import ReactGA from 'react-ga'; -import ReactTooltip from 'react-tooltip'; import Loading from '../../components/Loading'; import NavBar from '../../components/NavBar'; import { @@ -19,12 +19,13 @@ import { deleteBGroup, } from './actions'; import BGroupProjectOverview from './BGroupProjectOverview'; +import BGroupBuildingTable from './BGroupBuildingTable'; import completeProjectPropTypes from '../Project/propTypes'; import { loadProjects } from '../Project/actions'; -import AddressSearch from '../../components/AddressSearch/AddressSearch'; import userPropType from '../User/propTypes'; import request from '../../utils/request'; -import { getHeaders, accountURL, gatewayURL, contactsURL } from '../../utils/restServices'; +import { getHeaders, accountURL, gatewayURL, contactsURL, sfBuildingImpactURL } from '../../utils/restServices'; +import './styles.css'; const UTILITY_TYPES = { 1: 'electric', @@ -36,7 +37,6 @@ const UTILITY_TYPES = { /* eslint-disable no-param-reassign */ export class BGroup extends Component { state = { - edit: false, utilityAccountsStatus: {}, utilityLoading: false, utilityError: false, @@ -51,11 +51,12 @@ export class BGroup extends Component { projectStatusBreakdown: {}, contactAccounts: {}, contactParentAccounts: {}, - contactNames: {}, contactLoading: false, contactError: false, - numRows: -1, - overviewTab: this.props.user.permissions['view::bgroupProjectsSummary'] ? 'projects' : 'buildings', + impactLoading: false, + impactError: false, + impact: {}, + overviewTab: this.props.user.permissions['view::bgroupProjectsSummary'] && this.props.displayProjectOverview ? 'projects' : 'buildings', } componentDidMount() { @@ -72,13 +73,13 @@ export class BGroup extends Component { val.building_id )); if (buildingIds.length > 0) { - this.setState({ numRows: buildingIds.length }); this.props.loadProjects({ 'building_id[]': buildingIds }); this.getUtilityAccounts(buildingIds); if (this.props.user.permissions['read::Gateway']) { this.getGatewayDates(buildingIds); } this.getSimulationDates(buildingIds); + this.getSfBuildingImpact(buildingIds); } } if ( @@ -118,6 +119,27 @@ export class BGroup extends Component { clearTimeout(this.updateNumRows); } + getSfBuildingImpact = (buildingIds) => { + // A function to determine dates of gateway install + this.setState({ impactLoading: true }); + const filterString = buildingIds.reduce((acc, val) => ( + `${acc}building_id[]=${val}&` + ), ''); + request(`${sfBuildingImpactURL}?${filterString}`, { + method: 'GET', + headers: getHeaders(), + }).then((res) => { + this.setState({ impactLoading: false }); + const data = res.data; + if (!res.err && data) { + this.setState({ impact: data }); + } else { + this.setState({ impactError: true }); + } + }); + + } + getContacts = (projects) => { // A function to get all of the contact information for buildings this.setState({ contactLoading: true }); @@ -143,15 +165,13 @@ export class BGroup extends Component { if (!res.err && data) { const contactAccounts = {}; const contactParentAccounts = {}; - const contactNames = {}; data.map((val) => { const buildingId = salesForceToBuilding[val.sales_force_id]; contactAccounts[buildingId] = val.account_name; contactParentAccounts[buildingId] = val.parent_account_name; - contactNames[buildingId] = val.contacts.map(contact => contact.name); return val; }); - this.setState({ contactAccounts, contactParentAccounts, contactNames }); + this.setState({ contactAccounts, contactParentAccounts }); } else { this.setState({ contactError: true }); } @@ -242,23 +262,6 @@ export class BGroup extends Component { }); } - handleAddBuilding = (item) => { - this.props.addBuildingToBGroup( - this.props.params.bGroupId, - { building_ids: [item.building_id] }, - item.street_address, - ); - } - - handleDeleteBuilding = (buildingId) => { - if (confirm('Are you sure you want to delete this building from this group?')) { - this.props.deleteBuildingFromBGroup( - this.props.params.bGroupId, - buildingId, - ); - } - } - handleDeleteGroup = () => { const { name } = this.props.bGroup.bGroupDetail; if (confirm(`Are you sure you want to delete group ${name}? This action cannot be undone.`)) { @@ -273,7 +276,7 @@ export class BGroup extends Component { } if (this.state.edit) { return ( -
+
); } - renderProjectSummary = () => { - } - - renderDeleteBuildingButton = (id) => { - if (this.props.bGroup.deleteBGroupBuildingLoading[id]) { - return ( - - ); - } - const disabled = !this.props.user.permissions['delete::BuildingBGroup']; - return ( - (this.handleDeleteBuilding(id))} - style={{ cursor: disabled ? 'not-allowed' : 'pointer' }} - disabled={disabled} - /> - ); - } - - renderBuildingGroup = () => { - let { bGroupBuildings } = this.props.bGroup; - // A generic filter method that ensures that empty rows return false - const genericFilterMethod = (filter, row) => ( - row[filter.id] ? - row[filter.id].toLowerCase().indexOf( // eslint-disable-line - filter.value.toLowerCase() - ) !== -1 - : false - ); - - const utilityBillFilterMethod = (filter, row) => { - if (filter.value === 'all') { - return true; - } - if (filter.value === 'received') { - return row[filter.id]; - } - return !row[filter.id]; - }; - - const utilityBillFilter = ({ filter, onChange }) => ( - - ); - const columns = [{ - Header: () => ( - - Building Info{' '} - - - ), - columns: [ - { - Header: 'Address', - filterMethod: (filter, row) => ( - row._original.address_list.toLowerCase().indexOf( // eslint-disable-line - filter.value.toLowerCase() - ) !== -1 - ), - Filter: ({ filter, onChange }) => ( - onChange(event.target.value)} - /> - ), - accessor: 'first_address', - Cell: row => ( - {row.value} - ), - }, - ], - }, { - Header: () => ( - - Contact Info{' '} - - - ), - columns: [ - { - Header: 'Owner', - filterMethod: genericFilterMethod, - accessor: 'contact_account', - }, { - Header: 'Parent Company', - filterMethod: genericFilterMethod, - accessor: 'contact_parent_account', - }, { - Header: 'Contact Names', - filterMethod: (filter, row) => { - // Handle this one differently because it's a list - if (row[filter.id]) { - return row[filter.id].reduce((acc, val) => ( - val && (acc || val.toLowerCase().indexOf( - filter.value.toLowerCase() - ) !== -1) - ), false); - } - return false; - }, - accessor: 'contact_names', - Cell: row => (row.value ? ( -
    - {row.value.map((name, index) => ( -
  • {name}
  • - ))} -
- ) : null), - }, - ], - }, { - Header: () => ( - - Analysis{' '} - - - ), - columns: [ - { - Header: 'Electric Bill', - filterMethod: utilityBillFilterMethod, - Filter: utilityBillFilter, - accessor: 'electric_bill', - style: { textAlign: 'center' }, - Cell: row => (row.value ? : null), - }, { - Header: 'Gas Bill', - filterMethod: utilityBillFilterMethod, - Filter: utilityBillFilter, - accessor: 'gas_bill', - style: { textAlign: 'center' }, - Cell: row => (row.value ? : null), - }, { - Header: 'Energy Simulation', - filterMethod: (filter, row) => { - if (filter.value === 'all') { - return true; - } - if (filter.value === 'complete') { - return row[filter.id]; - } - return !row[filter.id]; - }, - Filter: ({ filter, onChange }) => ( - - ), - accessor: 'building_simulation', - style: { textAlign: 'center' }, - Cell: row => (row.value ? : null), - }, - ], - }, { - Header: () => ( - - Projects{' '} - - - ), - columns: [ - // Only show the sensor install column if the user has the correct permission - ...(!this.props.user.permissions['read::Gateway']) ? [] : [{ - Header: 'Sensor Install', - filterMethod: (filter, row) => { - if (filter.value === 'all') { - return true; - } - if (filter.value === 'installed') { - return row[filter.id]; - } - return !row[filter.id]; - }, - Filter: ({ filter, onChange }) => ( - - ), - accessor: 'gateway_install', - sortMethod: (a, b) => { - if (!b && a) { - return 1; - } else if (b && !a) { - return -1; - } else if (!b && !a) { - return 0; - } - const d1 = new Date(a[0]); - const d2 = new Date(b[0]); - if (d1.getTime() === d2.getTime()) { - return 0; - } - return d1 > d2 ? 1 : -1; - }, - Cell: row => (row.value ? ( -
    - {row.value.map((installDate, index) => ( -
  • {installDate}
  • - ))} -
- ) : null), - }], { - Header: '# Projects', - filterable: false, - style: { textAlign: 'center' }, - accessor: 'num_projects', - }, { - Header: 'Project Types', - filterMethod: (filter, row) => { - // Handle this one differently because it's a list - if (row[filter.id]) { - - return row[filter.id].reduce((acc, val) => ( - val && (acc || val.toLowerCase().indexOf( - filter.value.toLowerCase() - ) !== -1) - ), false); - } - return false; - }, - accessor: 'project_types', - Cell: row => (row.value ? ( -
    - {row.value.map((type, index) => ( -
  • {type}
  • - ))} -
- ) : null), - }, - ], - }]; - if (this.state.edit) { - columns.push({ - Header: '', - filterable: false, - accessor: 'delete', - maxWidth: 35, - Cell: row => this.renderDeleteBuildingButton(row.original.id), - }); - } - bGroupBuildings = bGroupBuildings.map((val) => { - const projects = this.state.buildingIdProject[val.building_id]; - if (projects) { - val.num_projects = projects.length; - val.project_types = projects.map(proj => (proj.project_type)); - } else { - val.num_projects = 0; - val.project_types = []; - } - const utilityStatus = this.state.utilityAccountsStatus[val.building_id]; - if (utilityStatus) { - val.electric_bill = utilityStatus.electric; - val.gas_bill = utilityStatus.gas; - } - val.gateway_install = this.state.gatewayDates[val.building_id]; - val.building_simulation = this.state.simulationDates[val.building_id]; - val.contact_account = this.state.contactAccounts[val.building_id]; - val.contact_parent_account = this.state.contactParentAccounts[val.building_id]; - val.contact_names = this.state.contactNames[val.building_id]; - return val; - }); - return ( -
-
-
- - -
-
-
= 0 ? '' : 'none' }}> -
-
{this.state.numRows} buildings
-
-
-
-
- { this.reactTable = reactTable; }} - onFilteredChange={(filter) => { - // Create a bounce function so as to not decrease the speed of the filter. - clearTimeout(this.updateNumRows); - this.updateNumRows = setTimeout( - () => { - ReactGA.event({ - category: 'Building Group', - action: 'Filter', - label: filter.reduce((acc, val) => { - return ( - `${acc}, ${val.id}: ${val.value}` - ); - }, `Building Group: ${this.props.bGroup.bGroupDetail.name}, # Results: ${this.reactTable.state.sortedData.length}`), - }); - this.setState({ - numRows: this.reactTable.state.sortedData.length, - }); - }, - 250, - ); - }} - noDataText={this.props.bGroup.bGroupDetailLoading ? 'Loading...' : 'No data'} - SubComponent={row => { - const addresses = bGroupBuildings - .filter(i => i.building_id === row.original.building_id) - .reduce((acc, val) => val.address_list, '') - .split(','); - return ( -
- -
-
-

- Address list{' '} - - - -

-
    - {addresses.map(i =>
  • {i}
  • )} -
-
- {this.state.buildingIdProject[row.original.building_id] ? ( -
-

- Project list -

-
    - {this.state.buildingIdProject[row.original.building_id].map((i) => { - let spanStatus = 'pending'; - if (i.state === 'constructed') { - spanStatus = 'claimed'; - } else if (i.state === 'cancelled') { - spanStatus = 'rejected'; - } - return ( -
  • - { i.state } - {' '} - { i.project_type } - {' '} - {i.name} -
  • - ); - })} -
-
- ) : null} -
-
- ); - }} - /> -
-
-
- ); - } - render() { let content = ( @@ -710,7 +311,33 @@ export class BGroup extends Component { ); break; case 'buildings': - content = this.renderBuildingGroup(); + content = ( + + ); break; default: content = 'There was an error'; @@ -719,11 +346,11 @@ export class BGroup extends Component { return (
- + {this.props.displayNavBar ? : null}
-
+
View all groups {' '}

-