this.handleSelectFilter(rowKey, filterAttrs) } key={rowKey} onIgnoreAll={onIgnoreAll}\n disputeLedgerItems={disputeLedgerItems}\n ignoreReason={ignoreReason}\n serviceCode={serviceCode} reason={reason}/ >\n })\n })\n }).flatten().value()\n\n content = (\n \n \n \n Count \n Service Code \n Reason \n Ignore Reason \n Actions \n \n \n \n {rows}\n \n
\n )\n\n }\n\n return (\n\n \n \n \n \n \n \n Dispute Summary\n \n \n {\n minimized ? null : \n { content }\n \n }\n \n )\n }\n}\n\n\nDisputeSummary.propTypes = {\n};\n\n\nconst mapStateToProps = (state, { } ) => {\n\n var vendorInvoice = getVendorInvoice(state)\n var disputeLedgerItems = _.filter(getDisputeLedgerItems(state), ({lineItemId}) => {\n var item = getLineItem(lineItemId, state)\n return item && item.vendorInvoiceId == vendorInvoice.id }\n )\n\n return {\n disputeLedgerItems\n }\n}\n\nconst mapDispatchToProps = (dispatch, {}) => {\n return {\n onIgnoreAll: (ignoreReason, ids) => dispatch(submitIgnoreDisputes(ignoreReason, ids)),\n onFilter: (filterAttrs) => {\n dispatch(appActions.setDisputeFilter(filterAttrs))\n dispatch(appActions.selectLocationFilter('Selected Disputes'))\n }\n\n }\n}\n\nDisputeSummary = connect(\n mapStateToProps,\n mapDispatchToProps\n)(DisputeSummary)\n\n\nexport default DisputeSummary;\n\n\n\n\n\n\n","import _ from 'lodashExtended'\nimport { createSelector } from 'reselect'\n\nconst isStateNotLoaded = (state) => {\n return !_.isPresent(state.api)\n}\n\n//const isStateNotLoaded = (state) => {\n //return !_.isPresent(state.api)\n//}\n\n\nconst getDataLoadPaths = (state) => {\n return state.api.dataLoadPaths\n}\n\n\nconst getLoadProgress = createSelector(\n [\n getDataLoadPaths\n ],\n (\n dataLoadPaths\n ) => {\n\n if(dataLoadPaths) {\n\n let totalCount = _.size(Object.keys(dataLoadPaths))\n let loadedCount = _(dataLoadPaths).filter((v,k) => v == 'loaded').size()\n return {totalCount, loadedCount}\n }\n }\n)\n\nconst allLocationsLoaded = (state) => {\n let {totalCount, loadedCount} = getLoadProgress(state)\n return totalCount == loadedCount\n}\n\nexport {\n getLoadProgress,\n isStateNotLoaded,\n allLocationsLoaded\n}\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport { connect } from 'react-redux';\n\nimport _ from 'lodashExtended'\nimport { getAgreements } from '../agreements/selectors'\nimport appActions from '../app/actions'\nimport { getLocationFilter, getCurrentFilterResults, getLocationFilterCounts } from '../app/selectors'\nimport { getStats } from '../stats/selectors'\nimport Location from './Location'\nimport ValidationBtn from './ValidationBtn'\nimport MatchBtn from './MatchBtn'\nimport UnmatchedSummary from './UnmatchedSummary'\nimport DisputeSummary from './DisputeSummary'\nimport { isStateNotLoaded } from '../api/selectors'\nimport { getReconcilePolicyName, getMatchPolicyName } from '../vendorInvoice/selectors'\nimport { Badge, Label, NavItem, Nav, Button } from 'react-bootstrap'\n\n\nlet DefaultMode = ({\n locationIds,\n stats,\n selectedFilter,\n agreementIds,\n filterCounts,\n onSelectFilter,\n matchPolicyName,\n reconcilePolicyName\n}) => {\n\n return(\n \n
\n \n \n
\n\n
\n {_.map(filterCounts,([filter, count]) => {\n\n return \n {filter} {count} \n \n }) }\n\n \n
\n {reconcilePolicyName} {matchPolicyName} \n {\" \" || stats.validation.percentage} \n
\n\n
\n {\n _.map(locationIds, (id) => {\n return( )\n })\n }\n
\n
\n )\n}\n\nDefaultMode.propTypes = {\n stats: PropTypes.exact({\n validation: PropTypes.exact({\n percentage: PropTypes.string,\n percentageColor: PropTypes.string\n }),\n timestamp: PropTypes.number\n })\n}\n\nconst mapStateToProps = (state, props) => {\n return {\n stats: getStats(state),\n selectedFilter: getLocationFilter(state),\n filterCounts: getLocationFilterCounts(state),\n ...getCurrentFilterResults(state),\n reconcilePolicyName: getReconcilePolicyName(state),\n matchPolicyName: getMatchPolicyName(state)\n }\n}\n\nconst mapDispatchToProps = (dispatch, ownProps) => {\n return {\n onSelectFilter: (filter) => { dispatch(appActions.selectLocationFilter(filter))}\n }\n}\n\nDefaultMode = connect(\n mapStateToProps,\n mapDispatchToProps\n)(DefaultMode)\n\nexport default DefaultMode\n\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport { connect } from 'react-redux';\nimport { getMatchModeNavLocationIds } from '../app/selectors'\nimport appActions from '../app/actions'\nimport _ from 'lodashExtended'\nimport { getLocation } from '../locations/selectors'\nimport Location from './Location'\nimport ValidationBtn from './ValidationBtn'\nimport MatchBtn from './MatchBtn'\nimport UnmatchedSummary from './UnmatchedSummary'\nimport DisputeSummary from './DisputeSummary'\nimport { allLocationsLoaded } from '../api/selectors'\nimport { Btn } from 'sharedComponents'\n\n\nlet MatchMode = ({\n location,\n nextLocation,\n backLocation,\n matchPolicyName,\n reconcilePolicyName,\n matchedCount,\n totalCount,\n onChangeLocationId,\n allLocationsLoaded\n}) => {\n\n\n\n let blankLocationNotice = (\n \n { nextLocation ?\n onChangeLocationId(nextLocation.id)}>\n Click here to start matching!\n \n : allLocationsLoaded ? All Done. Nothing to Match : No Locations to Match yet. Waiting for loading to finish... \n }\n
\n )\n\n\n return(\n \n
\n { backLocation ?\n
onChangeLocationId(backLocation.id)}>\n {backLocation.postcodeIdName}\n
:
}\n
\n Matching Progress: { matchedCount } / { totalCount }\n
\n { nextLocation ?\n
onChangeLocationId(nextLocation.id)}>\n {nextLocation.postcodeIdName} \n
:
}\n
\n
\n {location ? : blankLocationNotice }\n
\n
\n )\n}\n\nMatchMode.propTypes = {\n\n}\n\nconst mapStateToProps = (state, props) => {\n\n const {\n nextLocationId,\n backLocationId,\n currentLocationId,\n matchedCount,\n totalCount,\n } = getMatchModeNavLocationIds(state)\n\n return {\n location: getLocation(currentLocationId, state),\n nextLocation: getLocation(nextLocationId, state),\n backLocation: getLocation(backLocationId, state),\n reconcilePolicyName: state.vendorInvoice.reconcilePolicyName,\n matchPolicyName: state.vendorInvoice.matchPolicyName,\n matchedCount,\n totalCount,\n allLocationsLoaded: allLocationsLoaded(state)\n }\n}\n\nconst mapDispatchToProps = (dispatch, ownProps) => {\n return {\n onChangeLocationId: (locationId) => {\n dispatch(appActions.setMatchModeLocationId(locationId))\n },\n }\n}\n\nMatchMode = connect(\n mapStateToProps,\n mapDispatchToProps\n)(MatchMode)\n\nexport default MatchMode\n\n","import { createAction } from 'redux-act';\n\nconst loadSuccess = createAction(\"report has been loaded success from server\", (loadedHwcns) => { return( { loadedHwcns } ) });\n\nexport default {\n loadSuccess,\n}\n\n","import actions from './actions'\nimport agreementActions from '../agreements/actions'\nimport failureReportActions from '../failureReports/actions'\nimport locationActions from '../locations/actions'\nimport lineItemActions from '../lineItems/actions'\nimport hwcnActions from '../hwcns/actions'\nimport submitToServer from 'submitToServer'\nimport _ from 'lodashExtended'\n\n\n\n// request every 1000 milliseconds. Rate limit the api request to Vector so it doesnt DoS Attack itself\nvar throttle = require('promise-ratelimit')(1000); /* rateInMilliseconds */\nvar fasterThrottle = require('promise-ratelimit')(333); /* rateInMilliseconds */\n\nconst loadState = () => (dispatch, getState) => {\n\n const state = getState()\n const submitPath = state.loadStatePath\n\n submitToServer(submitPath, '',\n (data,v) => {\n\n dispatch(actions.stateLoaded(data))\n _.each(Object.values(data.api.dataLoadPaths), (path) => {\n (data.api.isLondonBusinessHours ? throttle : fasterThrottle)().then( () => {\n dispatch(loadLocationData(path))\n })\n }\n )\n },\n (data, status) => {\n data\n alert(`There was an issue with the server, Please contact support, support@anenta.com (status: ${status})`)\n }, { method: 'GET' }\n )\n\n}\n\nconst loadLocationData = (path) => (dispatch, getState) => {\n\n submitToServer(path, '',\n (data,v) => {\n\n if(data.failureReports) {\n dispatch(failureReportActions.loadSuccess(data.failureReports.byId))\n }\n if(data.agreements) {\n dispatch(agreementActions.loadSuccess(data.agreements.byId))\n }\n if(data.locations) {\n dispatch(locationActions.loadSuccess(data.locations.byId))\n }\n if(data.lineItems) {\n dispatch(lineItemActions.loadSuccess(data.lineItems.byId))\n }\n if(data.hwcns) {\n dispatch(hwcnActions.loadSuccess(data.hwcns.byId))\n }\n },\n (data, status) => {\n data\n alert(`There was an issue with the server, Please contact support, support@anenta.com (status: ${status})`)\n }, { method: 'GET' }\n )\n\n}\n\n\n\nexport {\n loadState\n}\n\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport { connect } from 'react-redux';\n\nimport _ from 'lodashExtended'\nimport DefaultMode from './DefaultMode'\nimport MatchMode from './MatchMode'\nimport { enterMatchMode, exitMatchMode } from '../app/operations'\nimport { loadState } from '../api/operations'\nimport { isStateNotLoaded, getLoadProgress } from '../api/selectors'\nimport { inMatchMode } from '../app/selectors'\nimport { Button } from 'react-bootstrap'\n\nclass App extends React.Component {\n\n //componentDidMount() {\n //if(this.props.stateNotLoaded) { this.props.loadState() }\n //}\n\n constructor(props) {\n super(props);\n this.state = {appNotBooted: true};\n }\n\n\n render() {\n\n const {loadState, stateNotLoaded, loadProgress, matchingMode, onChangeMode} = this.props\n const {appNotBooted} = this.state\n\n\n if(appNotBooted) {\n return(\n \n {\n this.setState({appNotBooted: false})\n loadState()\n }\n }>CLICK TO LOAD \n
\n )\n } else if(stateNotLoaded) {\n return(\n \n \n
Loading App... \n \n )\n } else {\n\n let loadProgressNode\n if(loadProgress && loadProgress.loadedCount != loadProgress.totalCount) {\n loadProgressNode = (\n \n
Loading Locations {loadProgress.loadedCount}/{loadProgress.totalCount} \n )\n }\n\n if(matchingMode) {\n return(\n \n {loadProgressNode}\n { onChangeMode(false) }}>Exit MATCH MODE \n { onChangeMode(false) }}/>\n
\n )\n } else {\n return(\n \n {loadProgressNode}\n { onChangeMode(true) }}>Go To MATCH MODE \n { onChangeMode(true) }}/>\n
\n )\n }\n }\n }\n}\n\nApp.propTypes = {\n\n}\n\nconst mapStateToProps = (state, props) => {\n return {\n stateNotLoaded: isStateNotLoaded(state),\n loadProgress: getLoadProgress(state),\n matchingMode: inMatchMode(state),\n ...state,\n }\n}\n\nconst mapDispatchToProps = (dispatch, ownProps) => {\n return {\n loadState: () => dispatch(loadState()),\n onChangeMode: (bool) => {\n dispatch(bool ? enterMatchMode() : exitMatchMode() )\n }\n }\n}\n\nApp = connect(\n mapStateToProps,\n mapDispatchToProps\n)(App)\n\nexport default App\n","import locationActions from '../locations/actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\n\n\nvar d = dotProp\n\nconst reducer = createReducer({\n [locationActions.loadSuccess]: (api, { loadedLocations } ) => {\n return _.reduce(Object.keys(loadedLocations), (result, locationId) => {\n return d.set(result, `dataLoadPaths.${locationId}`, 'loaded')\n }, api)\n },\n},\n{})\n\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as apiActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport appActions from '../app/actions'\nimport { createReducer } from 'redux-act'\nimport moment from 'moment'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\nimport { keyToDate, keyToNumber } from '../app/utils'\n\nvar d = dotProp\n\nconst {\n submitSuccess,\n submitError,\n submitStart,\n setDate,\n setSpecQuantity,\n setReconcilePolicy,\n closeAgreementForm,\n setSpecAgreementForm,\n submitStartAgreementForm,\n setAgreementForm,\n destroy,\n loadSuccess\n} = actions\n\nconst reducer = createReducer({\n [loadSuccess]: (agreements, { loadedAgreements } ) => {\n return _.reduce(loadedAgreements, (result, agreement) => {\n return d.set(result, `byId.${agreement.id}`, agreement)\n }, agreements)\n },\n [submitSuccess]: (agreements, { updatedAgreements } ) => {\n return _.reduce(updatedAgreements, (result, updatedAgreement) => {\n if(updatedAgreement._destroy == '1') {\n return d.delete(result, `byId.${updatedAgreement.id}`)\n } else {\n return d.set(result, `byId.${updatedAgreement.id}`, updatedAgreement)\n }\n }, agreements)\n },\n [submitError]: (agreements, { updatedAgreements } ) => {\n return _.reduce(updatedAgreements, (result, {id}) => {\n return d.merge(result, `byId.${id}`, { submitting: false })\n }, agreements)\n },\n [submitStart]: (agreements, { ids } ) => {\n return _.reduce(ids, (result, id) => {\n return d.merge(result, `byId.${id}`, { submitting: true })\n }, agreements)\n },\n [destroy]: (agreements, { ids } ) => {\n return _.reduce(ids, (result, id) => {\n return d.merge(result, `byId.${id}`, { saved: false, _destroy: '1' })\n }, agreements)\n },\n [setSpecQuantity]: (agreements, { id, serviceCode, quantity } ) => {\n if(quantity >= 0) {\n const updatedAgreements = d.merge(agreements, ['byId', id, 'specifications', serviceCode], { serviceCode, quantity })\n return d.merge(updatedAgreements, `byId.${id}`, { saved: false, reconcilePolicyName: 'nothing' })\n } else {\n return agreements\n }\n },\n [setDate]: (agreements, { id, date }) => {\n var oldDate = dotProp.get(agreements, `byId.${id}.date`)\n if(date != oldDate) {\n return dotProp.merge(agreements, `byId.${id}`, { saved: false, date })\n } else {\n return agreements\n }\n },\n [setReconcilePolicy]: (agreements, { id, reconcilePolicyName }) => {\n return dotProp.merge(agreements, `byId.${id}`, { saved: false, reconcilePolicyName })\n },\n [setAgreementForm]: (agreements, { locationId, date, otherArgs }) => {\n return dotProp.merge(agreements, `forms.agreement.${locationId}.${date}`, { ...otherArgs, locationId, date } )\n },\n [closeAgreementForm]: (agreements, { locationId, date, serviceId }) => {\n return dotProp.delete(agreements, `forms.agreement.${locationId}.${date}`)\n },\n [setSpecAgreementForm]: (agreements, { locationId, date, newSpecs }) => {\n return dotProp.merge(agreements, `forms.agreement.${locationId}.${date}`, { agreedSpecifications: newSpecs } )\n },\n [submitStartAgreementForm]: (agreements, { locationId, date }) => {\n return dotProp.merge(agreements, `forms.agreement.${locationId}.${date}`, { submitting: true } )\n },\n},\n{ byId: {} } )\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as agreementsActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport appActions from '../app/actions'\nimport agreementActions from '../agreements/actions'\n\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\nimport { keyToDate } from '../app/utils'\n\nconst {\n submitSuccess,\n submitError,\n submitStart,\n setDate,\n updateFromServer,\n loadSuccess\n} = actions\n\nvar d = dotProp\n\nconst reducer = createReducer({\n [loadSuccess]: (lineItems, { loadedLineItems } ) => {\n return _.reduce(loadedLineItems, (result, lineItem) => {\n return d.set(result, `byId.${lineItem.id}`, lineItem)\n }, lineItems)\n },\n [submitSuccess]: (lineItems, { updatedLineItems } ) => {\n return _.reduce(updatedLineItems, (result, updatedLineItem) => {\n return d.set(result, `byId.${updatedLineItem.id}`, updatedLineItem)\n }, lineItems)\n },\n [submitError]: (lineItems, { updatedLineItems } ) => {\n return _.reduce(updatedLineItems, (result, {id}) => {\n return d.merge(result, `byId.${id}`, { submitting: false })\n }, lineItems)\n },\n [submitStart]: (lineItems, { ids } ) => {\n return _.reduce(ids, (result, id) => {\n return d.merge(result, `byId.${id}`, { submitting: true })\n }, lineItems)\n },\n [setDate]: (lineItems, { id, date }) => {\n var oldDate = dotProp.get(lineItems, `byId.${id}.date`)\n if(date != oldDate) {\n return dotProp.merge(lineItems, `byId.${id}`, { saved: false, date, agreementId: null })\n } else {\n return lineItems\n }\n },\n [updateFromServer]: (lineItems, { updatedItems } ) => {\n return _.reduce(updatedItems, (result, updatedItem) => {\n if(updatedItem._destroy == '1') {\n return d.delete(result, `byId.${updatedItem.id}`)\n } else {\n return d.set(result, `byId.${updatedItem.id}`, updatedItem)\n }\n }, lineItems)\n },\n [agreementActions.destroy]: (lineItems, { ids } ) => {\n const lineItemIds = _(lineItems.byId).map(({agreementId, id}) => _.includes(ids, agreementId) ? id : null).compact().value()\n return _.reduce(lineItemIds, (result, id) => {\n return d.merge(result, `byId.${id}`, { agreementId: null })\n }, lineItems)\n },\n},\n{})\n\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as lineItemsActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\n\nconst {\n locationsMatchStart,\n locationsMatchEnd,\n loadSuccess\n} = actions\n\nvar d = dotProp\n\nconst reducer = createReducer({\n [loadSuccess]: (locations, { loadedLocations } ) => {\n return _.reduce(loadedLocations, (result, location) => {\n return d.set(result, `byId.${location.id}`, location)\n }, locations)\n },\n [locationsMatchEnd]: (locations, { locationIds } ) => {\n return _.reduce(locationIds, (result, id) => {\n return d.merge(result, `byId.${id}`, { matching: false })\n }, locations)\n },\n [locationsMatchStart]: (locations, { locationIds } ) => {\n return _.reduce(locationIds, (result, id) => {\n return d.merge(result, `byId.${id}`, { matching: true })\n }, locations)\n },\n},\n{})\n\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as locationsActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\n\nconst d = dotProp\n\nconst {\n updateFromServer,\n newDisputeForm,\n //deleteFromServer\n} = actions\n\nconst reducer = createReducer({\n [updateFromServer]: (disputeLedgerItems, { updatedItems } ) => {\n return _.reduce(updatedItems, (result, updatedItem) => {\n if(updatedItem._destroy == '1') {\n return d.delete(result, `byId.${updatedItem.id}`)\n } else {\n return d.set(result, `byId.${updatedItem.id}`, updatedItem)\n }\n }, disputeLedgerItems)\n },\n [newDisputeForm]: (app, { lineItemIds }) => {\n return dotProp.set(app, 'forms.newDispute', { lineItemIds } )\n },\n},\n{})\n\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as disputeLedgerItemsActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\n\nconst {\n submitSuccess,\n submitError,\n submitStart,\n updateReport,\n loadSuccess\n} = actions\n\nvar d = dotProp\n\nconst reducer = createReducer({\n [loadSuccess]: (failureReports, { loadedFailureReports } ) => {\n return _.reduce(loadedFailureReports, (result, failureReport) => {\n return d.set(result, `byId.${failureReport.id}`, failureReport)\n }, failureReports)\n },\n [submitSuccess]: (failureReports, { updatedFailureReports } ) => {\n return _.reduce(updatedFailureReports, (result, updatedFailureReport) => {\n return d.set(result, `byId.${updatedFailureReport.id}`, updatedFailureReport)\n }, failureReports)\n },\n [submitError]: (failureReports, { updatedFailureReports } ) => {\n return _.reduce(updatedFailureReports, (result, {id}) => {\n return d.merge(result, `byId.${id}`, { submitting: false })\n }, failureReports)\n },\n [submitStart]: (failureReports, { ids } ) => {\n return _.reduce(ids, (result, id) => {\n return d.merge(result, `byId.${id}`, { submitting: true })\n }, failureReports)\n },\n [updateReport]: (failureReports, { id, newArgs } ) => {\n return d.merge(failureReports, `byId.${id}`, { ...newArgs, saved: false })\n }\n},\n{})\n\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as failureReportsActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\n\n\nconst {\n\n loadSuccess\n} = actions\n\nvar d = dotProp\n\nconst reducer = createReducer({\n [loadSuccess]: (hwcns, { loadedHwcns } ) => {\n return _.reduce(loadedHwcns, (result, hwcn) => {\n return d.set(result, `byId.${hwcn.id}`, hwcn)\n }, hwcns)\n },\n},\n{})\n\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as hwcnsActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\n\nconst {\n listenKeyDown,\n unListenKeyDown,\n keyDownEvent,\n selectLocationFilter,\n toggleLocationOpen,\n setDisputeFilter,\n setManualFilter,\n setUnmatchedFilter,\n setMatchMode,\n setMatchModeLocationId\n} = actions\n\nconst reducer = createReducer({\n [setMatchMode]: (app, bool) => {\n\n let result = dotProp.set(app, 'matchMode', bool)\n if(!bool) {\n result = dotProp.set(result, `matchModeList`, [])\n result = dotProp.delete(result, `matchModeLocationId`)\n }\n return result\n },\n [listenKeyDown]: (app, keyDownActionAgrs ) => {\n return dotProp.set(app, 'keyboard.listenKeyDown', keyDownActionAgrs )\n },\n [unListenKeyDown]: (app) => {\n return dotProp.delete(app, 'keyboard.listenKeyDown')\n },\n [selectLocationFilter]: (app, { filter }) => {\n return dotProp.set(app, 'filters.location', filter)\n },\n [keyDownEvent]: (app, { key }) => {\n if(key == 'Escape') {\n return dotProp.delete(app, 'keyboard.listenKeyDown')\n } else {\n return app\n }\n },\n [toggleLocationOpen]: (app, { locationId, open }) => {\n if(open == undefined) {\n return dotProp.toggle(app, `locationSectionOpen.${locationId}`)\n } else {\n return dotProp.set(app, `locationSectionOpen.${locationId}`, open)\n }\n },\n [setDisputeFilter]: (app, attrs) => {\n if(attrs) {\n return dotProp.set(app, `filters.disputeLedgerItemAttrs`, attrs)\n } else {\n return dotProp.delete(app, `filters.disputeLedgerItemAttrs`)\n }\n },\n [setManualFilter]: (app, attrs) => {\n if(attrs) {\n return dotProp.set(app, `filters.manualItemFilterAttrs`, attrs)\n } else {\n return dotProp.delete(app, `filters.manualItemFilterAttrs`)\n }\n },\n [setUnmatchedFilter]: (app, attrs) => {\n if(attrs) {\n return dotProp.set(app, `filters.unmatchedItemAttrs`, attrs)\n } else {\n return dotProp.delete(app, `filters.unmatchedItemAttrs`)\n }\n },\n [setMatchModeLocationId]: (app, locationId) => {\n let matchModeList = dotProp.get(app, `matchModeList`)\n let result = app\n if(!_.includes(matchModeList, locationId)) {\n result = dotProp.set(result, `matchModeList`, _.compact([...matchModeList, locationId]))\n }\n result = dotProp.set(result, `matchModeLocationId`, locationId)\n return result\n },\n\n\n},\n {\n matchMode: false,\n matchModeList: [],\n filters: { location: 'All' }\n })\n\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as appActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\n\nconst {\n submitSuccess,\n submitError,\n submitStart,\n setAgreementId,\n updateFromServer\n} = actions\n\nvar d = dotProp\n\nconst reducer = createReducer({\n [submitSuccess]: (salesLedgerItems, { updatedLineItems } ) => {\n return _.reduce(updatedLineItems, (result, updatedLineItem) => {\n return d.set(result, `byId.${updatedLineItem.id}`, updatedLineItem)\n }, salesLedgerItems)\n },\n [submitError]: (salesLedgerItems, { updatedLineItems } ) => {\n return _.reduce(updatedLineItems, (result, {id}) => {\n return d.merge(result, `byId.${id}`, { submitting: false })\n }, salesLedgerItems)\n },\n [submitStart]: (salesLedgerItems, { ids } ) => {\n return _.reduce(ids, (result, id) => {\n return d.merge(result, `byId.${id}`, { submitting: true })\n }, salesLedgerItems)\n },\n [setAgreementId]: (salesLedgerItems, { id, agreementId } ) => {\n var oldAgreementId = dotProp.get(salesLedgerItems, `byId.${id}.agreementId`)\n if(agreementId != oldAgreementId) {\n return dotProp.merge(salesLedgerItems, `byId.${id}`, { saved: false, agreementId })\n } else {\n return salesLedgerItems\n }\n },\n [updateFromServer]: (salesLedgerItems, { updatedItems } ) => {\n return _.reduce(updatedItems, (result, updatedItem) => {\n if(updatedItem._destroy == '1') {\n return d.delete(result, `byId.${updatedItem.id}`)\n } else {\n return d.set(result, `byId.${updatedItem.id}`, updatedItem)\n }\n }, salesLedgerItems)\n }\n},\n{})\n\nexport default reducer\n","import reducer from './reducer'\n\nexport { default as salesLedgerItemsActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\n\nconst {\n setSpecificationForm,\n closeSpecificationForm,\n submitStart,\n submitSuccess,\n submitError,\n setCurrentSpecQuantity,\n setCurrentSpecFrequency\n} = actions\n\n\nvar d = dotProp\n\n\nconst reducer = createReducer({\n [setSpecificationForm]: (specifications, { serviceId, newSpecifications }) => {\n return dotProp.merge(specifications, `forms.specifications.${serviceId}`, { unitSpecifications: newSpecifications } )\n },\n [closeSpecificationForm]: (specifications, { serviceId }) => {\n return dotProp.delete(specifications, `forms.specifications.${serviceId}`)\n },\n [submitSuccess]: (specifications, { updatedSpecifications } ) => {\n return _.reduce(updatedSpecifications, (result, updatedSpecification) => {\n if(updatedSpecification._destroy == '1') {\n return d.delete(result, `byId.${updatedSpecification.id}`)\n } else {\n return d.set(result, `byId.${updatedSpecification.id}`, updatedSpecification)\n }\n }, specifications)\n },\n [submitStart]: (specifications, { serviceId }) => {\n return dotProp.merge(specifications, `forms.specifications.${serviceId}`, { submitting: true } )\n },\n [setCurrentSpecQuantity]: (specifications, { serviceId, serviceCode, quantity }) => {\n if(quantity >= 0) {\n return dotProp.merge(specifications, ['forms','specifications',serviceId,'unitSpecifications',serviceCode], { quantity, serviceCode } )\n } else {\n return specifications\n }\n },\n [setCurrentSpecFrequency]: (specifications, { serviceId, serviceCode, collectionPlanName }) => {\n return dotProp.merge(specifications, ['forms','specifications',serviceId,'unitSpecifications',serviceCode], { collectionPlanName, serviceCode } )\n },\n\n},\n {})\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as specificationsActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\n\nconst {\n updateFromServer,\n}\n = actions\n\nconst reducer = createReducer({\n [updateFromServer]: (stats, newStats ) => {\n return newStats\n },\n},\n{})\n\n\nexport default reducer\n\n","import { createAction } from 'redux-act';\n\nconst updateFromServer = createAction(\"stats updated\");\n\nexport default {\n updateFromServer,\n}\n\n","import reducer from './reducer'\n\nexport { default as statsActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\n\nconst {\n updateCurrentSpecificationId,\n} = actions\n\nconst reducer = createReducer({\n [updateCurrentSpecificationId]: (services, { serviceId, currentSpecificationId } ) => {\n return dotProp.merge(services, `byId.${serviceId}`, { currentSpecificationId })\n },\n},\n{})\n\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as servicesActions } from \"./actions\";\n\nexport default reducer\n","import { createReducer, createAction } from 'redux-act';\nimport dotProp from 'dot-prop-immutable'\nimport apiReducer from './api'\nimport agreementsReducer from './agreements'\nimport lineItemsReducer from './lineItems'\nimport locationsReducer from './locations'\nimport disputeLedgerItemsReducer from './disputeLedgerItems'\nimport failureReportsReducer from './failureReports'\nimport hwcnsReducer from './hwcns'\nimport appReducer from './app'\nimport salesLedgerItemsReducer from './salesLedgerItems'\nimport specificationsReducer from './specifications'\nimport statsReducer from './stats'\nimport servicesReducer from './services'\nimport reduceReducers from 'reduce-reducers'\nimport apiActions from './api/actions'\n\nconst updateStateReducer = createReducer({\n [apiActions.stateLoaded]: (state, loadedState) => {\n return loadedState\n }\n},\n{})\n\nconst rootReducer = (state = {}, action) => {\n return {\n ...state,\n api: apiReducer(state.api, action),\n agreements: agreementsReducer(state.agreements, action),\n specifications: specificationsReducer(state.specifications, action),\n services: servicesReducer(state.services, action),\n lineItems: lineItemsReducer(state.lineItems, action),\n locations: locationsReducer(state.locations, action),\n failureReports: failureReportsReducer(state.failureReports, action),\n hwcns: hwcnsReducer(state.hwcns, action),\n disputeLedgerItems: disputeLedgerItemsReducer(state.disputeLedgerItems, action),\n app: appReducer(state.app, action),\n salesLedgerItems: salesLedgerItemsReducer(state.salesLedgerItems, action),\n stats: statsReducer(state.stats, action)\n }\n\n}\n\nexport default reduceReducers(updateStateReducer, rootReducer)\n\n","import actions from './actions'\nimport submitToServer from 'submitToServer'\nimport { getSalesItemsPendingSubmit } from './selectors'\nimport { getPathAndMethod } from '../api/utils'\nimport _ from 'lodashExtended';\n\nconst debounceAlert = _.debounce((status) => alert(`There was an issue with the server, Please contact support, support@anenta.com (status: ${status})`), 5000)\n\nconst submitSalesLedgerItems = () => (dispatch, getState) => {\n\n const state = getState()\n if(state.api) {\n const basePath = state.api.salesLedgerItemsPath\n _.each(getSalesItemsPendingSubmit(state), (salesLedgerItem) => {\n\n const [submitPath, method] = getPathAndMethod(basePath, salesLedgerItem)\n if(method) {\n dispatch(actions.submitStart([salesLedgerItem.id]))\n //console.log([method, submitPath])\n submitToServer(submitPath, { sales_ledger_item: salesLedgerItem },\n (data,v) => {\n if(data.salesLedgerItem) {\n dispatch(actions.submitSuccess({salesLedgerItem: data.salesLedgerItem}))\n }\n },\n (data, status, e) => {\n //dispatch(actions.serverError())\n data\n debounceAlert(status)\n }, { method })\n }\n })\n }\n}\n\nexport {\n submitSalesLedgerItems\n}\n","import actions from './actions'\nimport agreementActions from '../agreements/actions'\nimport submitToServer from 'submitToServer'\nimport { getFailureReportsPendingSubmit } from './selectors'\nimport { getAgreementIdsForFailureReport} from '../agreements/selectors'\nimport { validateAgreements } from '../agreements/operations'\nimport { getPathAndMethod } from '../api/utils'\nimport _ from 'lodashExtended'\n\n\nconst debounceAlert = _.debounce((status) => alert(`There was an issue with the server, Please contact support, support@anenta.com (status: ${status})`), 5000)\n\nconst submitFailureReports = () => (dispatch, getState) => {\n\n const state = getState()\n if(state.api) {\n const basePath = state.api.failureReportsPath\n\n _.each(getFailureReportsPendingSubmit(state), (failureReport) => {\n\n const [submitPath, method] = getPathAndMethod(basePath, failureReport)\n if(method) {\n dispatch(actions.submitStart([failureReport.id]))\n //console.log([method, submitPath])\n submitToServer(submitPath, { missed_collection_report: failureReport },\n (data,v) => {\n if(data.agreement) {\n dispatch(agreementActions.submitSuccess({agreement: data.agreement}))\n }\n if(data.failureReport) {\n dispatch(actions.submitSuccess({failureReport: data.failureReport}))\n dispatch(validateAgreements(getAgreementIdsForFailureReport(data.failureReport.id, getState())))\n }\n },\n (data, status, e) => {\n //dispatch(actions.serverError())\n data\n debounceAlert(status)\n }, { method })\n }\n })\n }\n}\n\n\nexport {\n submitFailureReports\n}\n","import { createStore, applyMiddleware } from 'redux';\nimport rootReducer from './reducer'\nimport thunk from 'redux-thunk'\nimport { composeWithDevTools } from 'redux-devtools-extension/developmentOnly';\nimport { handleKeyDownEvent } from './app/operations'\nimport { getKeyDownListener } from './app/selectors'\nimport _ from 'lodashExtended'\nimport { getAgreements } from './agreements/selectors'\nimport { getLineItems } from './lineItems/selectors'\nimport { getSalesLedgerItems } from './salesLedgerItems/selectors'\nimport { getFailureReports } from './failureReports/selectors'\nimport { submitAgreements } from './agreements/operations'\nimport { submitLineItems } from './lineItems/operations'\nimport { submitSalesLedgerItems } from './salesLedgerItems/operations'\nimport { submitFailureReports } from './failureReports/operations'\nimport { loadStats } from './stats/operations'\n\n\nconst agreementObserver = _.debounce((selectedState, dispatch) => {\n dispatch(submitAgreements())\n}, 4000)\n\nconst lineItemObserver = _.debounce((selectedState, dispatch) => {\n dispatch(submitLineItems())\n}, 4000)\n\nconst salesLedgerItemObserver = _.debounce((selectedState, dispatch) => {\n dispatch(submitSalesLedgerItems())\n}, 4000)\n\nconst failureReportObserver = _.debounce((selectedState, dispatch) => {\n dispatch(submitFailureReports())\n}, 1000)\n\n//const stateObserver = _.throttle((selectedState, dispatch) => {\n //dispatch(loadStats())\n//}, 8000)\n\nfunction observeStore(store, select, onChange) {\n let currentState;\n\n function handleChange() {\n const state = store.getState()\n if(!state.loadStatePath) {\n let nextState = select === true ? null : select(state);\n if (select === true || nextState !== currentState) {\n currentState = nextState;\n onChange(currentState, store.dispatch);\n }\n }\n }\n\n let unsubscribe = store.subscribe(handleChange);\n handleChange();\n return unsubscribe;\n}\n\nconst listenToWindowEvent = (name, getListener, action) => (dispatch, getState) => {\n const handleEvent = (e) => {\n var { key } = e\n var listener = getListener(getState())\n if (listener) {\n if(_.includes(listener.preventDefaultKeys, key)) { e.preventDefault() }\n dispatch(action({listener, key}))\n }\n }\n window.addEventListener(name, handleEvent);\n // note: returns a function to unsubscribe\n return () => window.removeEventListener(name, handleEvent);\n}\n\nexport default function configureStore(initialState) {\n\n const store = createStore(rootReducer,\n initialState,\n composeWithDevTools(applyMiddleware(thunk)));\n\n if (module.hot) {\n module.hot.accept('./reducer', () => {\n //console.log('reload')\n const nextRootReducer = require('./reducer').default;\n store.replaceReducer(nextRootReducer);\n });\n }\n\n observeStore(store, getAgreements, agreementObserver)\n observeStore(store, getLineItems, lineItemObserver)\n observeStore(store, getSalesLedgerItems, salesLedgerItemObserver)\n observeStore(store, getFailureReports, failureReportObserver)\n //observeStore(store, true, stateObserver)\n\n store.dispatch(listenToWindowEvent('keydown', getKeyDownListener, handleKeyDownEvent));\n\n return store;\n\n}\n","import { hot } from 'react-hot-loader'\nimport App from './components/App'\nimport configureStore from './store'\n\nconst RootNode = hot(module)(App)\n\nexport {\n RootNode,\n configureStore\n}\n","import React from \"react\"\nimport { Provider } from 'react-redux';\nimport { RootNode, configureStore } from '../apps/validation'\n\nexport default (props) => {\n return (\n \n \n \n );\n}\n\n","import _ from \"lodashExtended\";\nimport {\n getAuditType,\n getSubmissionDate,\n getObservationResult\n} from \"../app/selectors\";\nimport emailAddressCheck from \"email-addresses\";\n\nconst isOnSite = state => {\n return getAuditType(state) == \"on_site\";\n};\n\nconst isOnSiteAndPresent = (value, state) => {\n return isOnSite(state) && isPresent(value, state);\n};\n\nconst isOnSiteAndYes = (value, state) => {\n return isOnSite(state) && isYes(value, state);\n};\n\nconst isOnSiteAndNo = (value, state) => {\n return isOnSite(state) && isNo(value, state);\n};\n\nconst isYes = (value, state) => {\n return value === \"yes\";\n};\n\nconst isNo = (value, state) => {\n return value === \"no\";\n};\n\nconst isBlank = (value, state) => {\n return _.isBlank(value);\n};\n\nconst isPresent = (value, state) => {\n return _.isPresent(value);\n};\n\nconst yearsFromSubmit = (date, state) => {\n const submissionDate = getSubmissionDate(state);\n return moment(submissionDate).diff(moment(date), \"year\");\n};\n\nconst monthsFromSubmit = (date, state) => {\n const submissionDate = getSubmissionDate(state);\n return moment(submissionDate).diff(moment(date), \"month\");\n};\n\nconst matchText = (value, regex, state) => {\n return _.isString(value) && _.isPresent(value.match(regex));\n};\n\nconst isEmail = (value, state) => {\n return _.isString(value) && emailAddressCheck.parseOneAddress(value);\n};\n\nconst wasteStreamDecisions = {\n hasStorage: [\n {\n score: 0,\n response: \"Site has bulk waste storage\",\n autoSelect: ({ hasStorage, ...x }, s) => {\n return isPresent(_.get(hasStorage, \"clearlyIdentified\"));\n }\n },\n {\n score: 3,\n response: \"Bulk storage of has not been reported\",\n action:\n \"Ensure that you have appropriate storage and disposal of general Waste in place for your practice. It is therefore not possible to assess how you dispose general waste and if the waste is correctly segregated. Refer to HTM 07-01 issued by the Department of Health and the EPR 5.07 issued by the Environment Agency and other guidelines to setup the appropriate waste disposal for your practice\",\n autoSelect: ({ hasStorage, ...x }, s) => {\n return hasStorage && isBlank(_.get(hasStorage, \"clearlyIdentified\"));\n }\n }\n ],\n storedSecurely: [\n {\n score: 0,\n response: \"The waste is stored securely\",\n autoSelect: ({ storedSecurely, ...x }, s) => {\n return (\n storedSecurely &&\n storedSecurely.containmentWithSecurityRequired.length > 0 &&\n isBlank(storedSecurely.notSecureContainment, s)\n );\n }\n },\n {\n score: 3,\n response: \"The waste is not stored securely\",\n action:\n \"Clinical waste has to be stored securely and not accessible to the public. Please ensure that the relevant requirements for Clinical waste storage are met for your practice. Please refer to HTM 07-01 issued by the Department of Health for guidance\",\n autoSelect: ({ storedSecurely, ...x }, s) => {\n return (\n storedSecurely &&\n storedSecurely.containmentWithSecurityRequired.length > 0 &&\n isPresent(storedSecurely.notSecureContainment, s)\n );\n }\n },\n {\n score: 3,\n response:\n \"No storage reported for clinical waste, storage security cannot be assessed\",\n action:\n \"Ensure that the relevant requirements for Clinical waste storage are met for your practice. Please refer to HTM 07-01 issued by the Department of Health for guidance\",\n autoSelect: ({ storedSecurely, ...x }, s) => {\n return (\n storedSecurely &&\n isBlank(storedSecurely.containmentWithSecurityRequired, s)\n );\n }\n }\n ],\n packagedCorrectly: [\n {\n score: 0,\n response: \"Waste is packaged in approved containers\",\n autoSelect: ({ packagedCorrectly, ...x }, s) => {\n return (\n packagedCorrectly &&\n packagedCorrectly.withPackagingRequired.length > 0 &&\n isBlank(packagedCorrectly.withoutCorrectPackaging, s)\n );\n }\n },\n {\n score: 3,\n response: \"Waste is not packaged in approved containers\",\n action:\n \"Ensure that your waste is correctly packaged. Refer to HTM 07-01 issued by the Department of Health and the EPR 5.07 issued by the Environment Agency and other guidelines to setup the appropriate waste disposal for your practice\",\n autoSelect: ({ packagedCorrectly, ...x }, s) => {\n return (\n packagedCorrectly &&\n packagedCorrectly.withPackagingRequired.length > 0 &&\n isPresent(packagedCorrectly.withoutCorrectPackaging, s)\n );\n }\n },\n {\n score: 3,\n response: \"No bulk storage reported, packaging cannot be assessed\",\n action:\n \"Ensure that your waste is correctly packaged. It is therefore not possible to assess how you dispose waste and if the waste is correctly packaged. Refer to HTM 07-01 issued by the Department of Health and the EPR 5.07 issued by the Environment Agency and other guidelines to setup the appropriate waste disposal for your practice\",\n autoSelect: ({ packagedCorrectly, ...x }, s) => {\n return (\n packagedCorrectly &&\n isBlank(packagedCorrectly.withPackagingRequired, s)\n );\n }\n }\n ],\n contaminationFound: [\n {\n score: 0,\n response: \"No Contamination found\",\n autoSelect: ({ contaminationFound }, s) => {\n return (\n contaminationFound &&\n isBlank(contaminationFound.withContamination, s) &&\n isPresent(contaminationFound.noContamination, s)\n );\n }\n },\n {\n score: 3,\n response:\n \"The identified contamination presents a severe risk. See Appendix B for details\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ contaminationFound }, s) => {\n return contaminationFound && contaminationFound.highestRiskLevel == 3;\n }\n },\n {\n score: 2,\n response:\n \"The contamination cannot be fully assesed and therefore presents a potential high risk. See Appendix A for details\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ contaminationFound }, s) => {\n return (\n contaminationFound &&\n isPresent(contaminationFound.cannotAssesContamination) &&\n contaminationFound.highestRiskLevel < 2\n );\n }\n },\n {\n score: 2,\n response:\n \"The identified contamination presents a high risk. See Appendix B for details\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ contaminationFound }, s) => {\n return contaminationFound && contaminationFound.highestRiskLevel == 2;\n }\n },\n {\n score: 1,\n response:\n \"The identified contamination presents a medium risk. See Appendix B for details\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ contaminationFound }, s) => {\n return contaminationFound && contaminationFound.highestRiskLevel == 1;\n }\n },\n {\n score: 0,\n response:\n \"The identified contamination presents a low risk. See Appendix B for details\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ contaminationFound }, s) => {\n return contaminationFound && contaminationFound.highestRiskLevel == 0;\n }\n },\n {\n score: 3,\n response:\n \"Insufficient information provided. The contamination cannot be assesed for this waste stream. See Appendix B for details\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ contaminationFound }, s) => {\n return (\n contaminationFound &&\n isBlank(contaminationFound.contaminationAssessed)\n );\n }\n },\n {\n score: 3,\n response: \"The waste stream has not been audited\",\n autoSelect: ({ id }, s) => isBlank(id, s)\n }\n ]\n};\n\nconst roomDecisions = {\n hasClinicalBins: [\n {\n score: 3,\n response: \"Room has not been audited\",\n autoSelect: ({ notAudited }, s) => notAudited\n },\n {\n score: 0,\n response: \"The room has at least one clinical waste bin identified\",\n autoSelect: ({ hasClinicalBins, ...x }, s) => {\n return isPresent(_.get(hasClinicalBins, \"clearlyIdentified\"));\n }\n },\n {\n score: 3,\n response:\n \"No clinical bins have been identified in this room. It is therefore not possible to assess how you dispose any clinical waste and if the waste is correctly segregated. \",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ hasClinicalBins, ...x }, s) => {\n return (\n hasClinicalBins &&\n isBlank(_.get(hasClinicalBins, \"clearlyIdentified\"))\n );\n }\n }\n ],\n hasNonClinicalBins: [\n {\n score: 2,\n response: \"The room has not been audited\",\n autoSelect: ({ notAudited }, s) => notAudited\n },\n {\n score: 0,\n response: \"The room has sufficient non clinical waste bins\",\n autoSelect: ({ hasNonClinicalBins, ...x }, s) => {\n return isPresent(_.get(hasNonClinicalBins, \"clearlyIdentified\"));\n }\n },\n {\n score: 2,\n response:\n \"No non-clinical waste bins have been identified in this room. It is therefore not possible to assess how you dispose any non clinical waste and if the waste is correctly segregated.\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ hasNonClinicalBins, ...x }, s) => {\n return (\n hasNonClinicalBins &&\n isBlank(_.get(hasNonClinicalBins, \"clearlyIdentified\"))\n );\n }\n }\n ],\n allRequiredContainersLabeled: [\n {\n score: 3,\n response: \"The room has not been audited\",\n autoSelect: ({ notAudited }, s) => notAudited\n },\n {\n score: 0,\n response: \"All clinical continers are labelled\",\n autoSelect: ({ allRequiredContainersLabeled }, s) => {\n return (\n allRequiredContainersLabeled &&\n allRequiredContainersLabeled.withLabelingRequired.length > 0 &&\n allRequiredContainersLabeled.withClearLabels.length ==\n allRequiredContainersLabeled.withLabelingRequired.length\n );\n }\n },\n {\n score: 3,\n response: \"All clinical containers are not labeled\",\n action:\n \"Ensure that your Clinical Waste Containers are labelled in accordance with the relevant regulatory requirements. Please refer to relevant guidelines such as the HTM 07-01 issued by the Department of Health\",\n autoSelect: ({ allRequiredContainersLabeled }, s) => {\n return (\n allRequiredContainersLabeled &&\n allRequiredContainersLabeled.withLabelingRequired.length > 0 &&\n isBlank(allRequiredContainersLabeled.withClearLabels, s)\n );\n }\n },\n {\n score: 2,\n response: \"Not all clinical containers are labeled\",\n action:\n \"Ensure that your Clinical Waste Containers are labelled in accordance with the relevant regulatory requirements. Please refer to relevant guidelines such as the HTM 07-01 issued by the Department of Health\",\n autoSelect: ({ allRequiredContainersLabeled }, s) => {\n return (\n allRequiredContainersLabeled &&\n allRequiredContainersLabeled.withLabelingRequired.length > 0 &&\n allRequiredContainersLabeled.withClearLabels.length !=\n allRequiredContainersLabeled.withLabelingRequired.length\n );\n }\n },\n {\n score: 3,\n response: \"No clinical containers were audited\",\n action:\n \"Ensure that your Clinical Waste Containers are labelled in accordance with the relevant regulatory requirements. Please refer to relevant guidelines such as the HTM 07-01 issued by the Department of Health\",\n autoSelect: ({ allRequiredContainersLabeled }, s) => {\n return (\n allRequiredContainersLabeled &&\n isBlank(allRequiredContainersLabeled.withLabelingRequired, s)\n );\n }\n }\n ],\n contaminationFound: [\n {\n score: 3,\n response: \"The room has not been audited\",\n autoSelect: ({ notAudited }, s) => notAudited\n },\n {\n score: 0,\n response: \"No Contamination found\",\n autoSelect: ({ contaminationFound }, s) => {\n return (\n contaminationFound &&\n isBlank(contaminationFound.withContamination, s) &&\n isPresent(contaminationFound.noContamination, s)\n );\n }\n },\n {\n score: 3,\n response:\n \"The identified contamination presents a severe risk. See Appendix A for details\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ contaminationFound }, s) => {\n return contaminationFound && contaminationFound.highestRiskLevel == 3;\n }\n },\n {\n score: 2,\n response:\n \"The contamination cannot be fully assesed and therefore presents a potential high risk. See Appendix A for details\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ contaminationFound }, s) => {\n return (\n contaminationFound &&\n isPresent(contaminationFound.cannotAssesContamination) &&\n contaminationFound.highestRiskLevel < 2\n );\n }\n },\n {\n score: 2,\n response:\n \"The identified contamination presents a high risk. See Appendix A for details\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ contaminationFound }, s) => {\n return contaminationFound && contaminationFound.highestRiskLevel == 2;\n }\n },\n {\n score: 1,\n response:\n \"The identified contamination presents a medium risk. See Appendix A for details\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ contaminationFound }, s) => {\n return contaminationFound && contaminationFound.highestRiskLevel == 1;\n }\n },\n {\n score: 0,\n response:\n \"The identified contamination presents a low risk. See Appendix A for details\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ contaminationFound }, s) => {\n return contaminationFound && contaminationFound.highestRiskLevel == 0;\n }\n },\n {\n score: 2,\n response:\n \"Insufficient information provided. The contamination cannot be assesed in this room and therefore presents a potential high risk. See Appendix A for details\",\n action:\n \"Ensure that the appropriate waste segregation is in place and that bins are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin outlining segregation requirement by waste type (What waste type should go in what bin type and what waste types not)\",\n autoSelect: ({ contaminationFound }, s) => {\n return (\n contaminationFound &&\n isBlank(contaminationFound.contaminationAssessed)\n );\n }\n }\n ]\n};\n\nconst externalBinDecisions = {\n clearlyIdentified: [\n {\n result: true,\n response: \"Clear image of the external container provided\",\n autoSelect: ({ exteriorPhoto }, s) => isOnSiteAndPresent(exteriorPhoto, s)\n },\n {\n result: false,\n response:\n \"No image provided. It is therefore not possible to assess whether the requirement has been met\",\n autoSelect: ({ exteriorPhoto }, s) => isBlank(exteriorPhoto, s)\n },\n {\n result: false,\n response:\n \"The image does not clearly show the external container. It is therefore not possible to assess whether the requirement has been met\"\n }\n ],\n contentsClearlyShown: [\n {\n result: true,\n response: \"Clear image of the contents provided\",\n autoSelect: ({ interiorPhoto }, s) => isOnSiteAndPresent(interiorPhoto, s)\n },\n {\n result: false,\n response:\n \"No image provided. It is therefore not possible to assess whether the requirement has been met\",\n autoSelect: ({ interiorPhoto }, s) => isBlank(interiorPhoto, s)\n },\n {\n result: false,\n response:\n \"The image does not clearly show the external container. It is therefore not possible to assess whether the requirement has been met\"\n }\n ],\n packagedCorrectly: [\n {\n result: true,\n response: \"Waste is packaged in approved containers\",\n autoSelect: ({ contaminants }, s) => {\n return isOnSite(s) && !_.get(contaminants, \"unpackagedWaste\");\n }\n },\n {\n result: false,\n response: \"Waste not packaged in approved containers\",\n autoSelect: ({ contaminants }, s) => {\n return !!_.get(contaminants, \"unpackagedWaste\");\n }\n },\n {\n result: false,\n response: \"No image provided. It is not possible to assess the packaging\",\n autoSelect: ({ interiorPhoto }, s) => isBlank(interiorPhoto, s)\n }\n ],\n isBinLocked: [\n {\n result: true,\n response: \"The containers are locked\",\n autoSelect: ({ isBinLocked }, s) => isOnSiteAndYes(isBinLocked, s)\n },\n {\n result: false,\n response: \"The containers are not locked\",\n autoSelect: ({ isBinLocked }, s) => isNo(isBinLocked, s)\n },\n {\n result: false,\n response:\n \"No Response, it is not possible to assess if the container is secure\",\n autoSelect: ({ isBinLocked }, s) => isBlank(isBinLocked, s)\n }\n ],\n isAreaLocked: [\n {\n result: true,\n response: \"The area is secure\",\n autoSelect: ({ isAreaLocked }, s) => isOnSiteAndYes(isAreaLocked, s)\n },\n {\n result: false,\n response: \"The area is not secure\",\n autoSelect: ({ isAreaLocked }, s) => isNo(isAreaLocked, s)\n },\n {\n result: false,\n response:\n \"No response, it is not possible to assess if the area is secure\",\n autoSelect: ({ isAreaLocked }, s) => isBlank(isAreaLocked, s)\n }\n ],\n contaminationFound: [\n {\n result: \"none\",\n response: \"No Contamination found\"\n },\n {\n result: 3,\n response: \"The identified contamination presents a severe risk\"\n },\n {\n result: 2,\n response: \"The identified contamination presents a high risk\"\n },\n {\n result: 1,\n response: \"The identified contamination presents a medium risk\"\n },\n {\n result: 0,\n response: \"The identified contamination presents a low risk\"\n },\n {\n result: \"cannot_assess\",\n response:\n \"No or insufficient information, contamination cannot be assesed.\"\n }\n ]\n};\n\nconst bulkContainmentDecisions = {\n clearlyIdentified: [\n {\n result: true,\n response: \"Clear image of area provided\",\n autoSelect: ({ bulkStorageAreaPhoto }, s) =>\n isOnSiteAndPresent(bulkStorageAreaPhoto, s)\n },\n {\n result: false,\n response:\n \"No image provided. It is therefore not possible to assess whether the requirement has been met\",\n autoSelect: ({ bulkStorageAreaPhoto }, s) =>\n isBlank(bulkStorageAreaPhoto, s)\n },\n {\n result: false,\n response:\n \"The image does not clearly show the area. It is therefore not possible to assess whether the requirement has been met\"\n }\n ],\n isPubliclyAccessible: [\n {\n result: true,\n response: \"The area is not accessible to the public\",\n autoSelect: ({ isPubliclyAccessible }, s) =>\n isOnSiteAndNo(isPubliclyAccessible, s)\n },\n {\n result: false,\n response: \"The area is accessible to the public\",\n autoSelect: ({ isPubliclyAccessible }, s) =>\n isYes(isPubliclyAccessible, s)\n },\n {\n result: false,\n response: \"No Response, The area may be accessible to the public\",\n autoSelect: ({ isPubliclyAccessible }, s) =>\n isBlank(isPubliclyAccessible, s)\n }\n ],\n isAreaLocked: [\n {\n result: true,\n response: \"The area is secure\",\n autoSelect: ({ isAreaLocked }, s) => isOnSiteAndYes(isAreaLocked, s)\n },\n {\n result: false,\n response: \"The area is not secure\",\n autoSelect: ({ isAreaLocked }, s) => isNo(isAreaLocked, s)\n },\n {\n result: false,\n response: \"No response. The area may not be secure\",\n autoSelect: ({ isAreaLocked }, s) => isBlank(isAreaLocked, s)\n }\n ],\n packagedCorrectly: [\n {\n result: true,\n response: \"Waste is packaged in approved containers\",\n autoSelect: ({ contaminants }, s) => {\n return isOnSite(s) && !_.get(contaminants, \"unpackagedWaste\");\n }\n },\n {\n result: false,\n response: \"Waste not packaged in approved containers\",\n autoSelect: ({ contaminants }, s) => {\n return !!_.get(contaminants, \"unpackagedWaste\");\n }\n },\n {\n result: false,\n response: \"No image provided. It is not possible to assess the packaging\",\n autoSelect: ({ bulkStorageAreaPhoto }, s) =>\n isBlank(bulkStorageAreaPhoto, s)\n }\n ],\n contaminationFound: [\n {\n result: \"none\",\n response: \"No Contamination found\"\n },\n {\n result: 3,\n response: \"The identified contamination presents a severe risk\"\n },\n {\n result: 2,\n response: \"The identified contamination presents a high risk\"\n },\n {\n result: 1,\n response: \"The identified contamination presents a medium risk\"\n },\n {\n result: 0,\n response: \"The identified contamination presents a low risk\"\n },\n {\n result: \"cannot_assess\",\n response:\n \"No or insufficient description, contamination cannot be assesed.\",\n autoSelect: ({ bulkStorageAreaPhoto }, s) =>\n isBlank(bulkStorageAreaPhoto, s)\n }\n ]\n};\n\nconst internalBinDecisions = {\n clearlyIdentified: [\n {\n result: true,\n response: \"Clear image of the container provided\",\n autoSelect: ({ exteriorPhoto }, s) => isOnSiteAndPresent(exteriorPhoto, s)\n },\n {\n result: false,\n response:\n \"No image provided. It is therefore not possible to assess whether the requirement has been met\",\n autoSelect: ({ exteriorPhoto }, s) => isBlank(exteriorPhoto, s)\n },\n {\n result: false,\n response:\n \"The image does not clearly show the container. It is therefore not possible to assess whether the requirement has been met\"\n }\n ],\n clearlyLabelled: [\n {\n result: true,\n response: \"Container is clearly labelled\",\n autoSelect: ({ hasCorrectLabel }, s) => isOnSiteAndYes(hasCorrectLabel, s)\n },\n {\n result: false,\n response: \"Container has not been labelled correctly or clearly\",\n autoSelect: ({ hasCorrectLabel }, s) => isNo(hasCorrectLabel, s)\n },\n {\n result: false,\n response: \"No image provided, label cannot be verified\",\n autoSelect: ({ exteriorPhoto }, s) => isBlank(exteriorPhoto, s)\n },\n {\n result: false,\n response: \"Image is not clear enough to verify label\"\n }\n ],\n contentsClearlyShown: [\n {\n result: true,\n response: \"Clear image of the contents provided\",\n autoSelect: ({ interiorPhoto }, s) => isOnSiteAndPresent(interiorPhoto, s)\n },\n {\n result: false,\n response:\n \"No image provided. It is therefore not possible to assess whether the requirement has been met\",\n autoSelect: ({ interiorPhoto }, s) => isBlank(interiorPhoto, s)\n },\n {\n result: false,\n response:\n \"The image does not clearly show the contents of the container. It is therefore not possible to assess whether the requirement has been met\"\n }\n ],\n contaminationFound: [\n {\n result: \"none\",\n response: \"No Contamination found\"\n },\n {\n result: 3,\n response: \"The identified contamination presents a severe risk\"\n },\n {\n result: 2,\n response: \"The identified contamination presents a high risk\"\n },\n {\n result: 1,\n response: \"The identified contamination presents a medium risk\"\n },\n {\n result: 0,\n response: \"The identified contamination presents a low risk\"\n },\n {\n result: \"cannot_assess\",\n response:\n \"No or insufficient information, contamination cannot be assesed.\",\n autoSelect: ({ interiorPhoto }, s) => isBlank(interiorPhoto, s)\n }\n ]\n};\n\nvar decisionData = {\n sections: {\n general_information: {\n email: [\n {\n score: 0,\n response: \"Information provided\",\n autoSelect: ({ email }, s) => isEmail(email, s)\n },\n {\n score: 0,\n response:\n \"Insufficient details provided, please ensure that the information is provided in full as part of your next audit\",\n autoSelect: ({ email }, s) => !isEmail(email, s)\n },\n {\n score: 0,\n response:\n \"Details not provided, please ensure that the information is provided in full as part of your next audit\",\n autoSelect: ({ email }, s) => isBlank(email, s)\n }\n ],\n clinicalEmployeeCount: [\n {\n score: 0,\n response: \"Information provided\",\n autoSelect: ({ clinicalEmployeeCount }, s) =>\n isPresent(clinicalEmployeeCount, s)\n },\n {\n score: 0,\n response:\n \"Details not provided, please ensure that the information is provided in full as part of your next audit\",\n autoSelect: ({ clinicalEmployeeCount }, s) =>\n isBlank(clinicalEmployeeCount, s)\n }\n ],\n clinicallyActiveRoomsCount: [\n {\n score: 0,\n response: \"Information provided\",\n autoSelect: ({ clinicallyActiveRoomsCount }, s) =>\n isPresent(clinicallyActiveRoomsCount, s)\n },\n {\n score: 0,\n response:\n \"Details not provided, please ensure that the information is provided in full as part of your next audit\",\n autoSelect: ({ clinicallyActiveRoomsCount }, s) =>\n isBlank(clinicallyActiveRoomsCount, s)\n }\n ],\n jobTitle: [\n {\n score: 0,\n response: \"Information provided\",\n autoSelect: ({ jobTitle }, s) => isOnSiteAndPresent(jobTitle, s)\n },\n {\n score: 0,\n response:\n \"Insufficient details provided, please ensure that the information is provided in full as part of your next audit\"\n },\n {\n score: 0,\n response:\n \"Details not provided, please ensure that the information is provided in full as part of your next audit\",\n autoSelect: ({ jobTitle }, s) => isBlank(jobTitle, s)\n }\n ],\n hasKnowledgeOfHtm0701: [\n {\n score: 0,\n response:\n \"The person conducting the audit has working knowledge of HTM 07-01\",\n autoSelect: ({ hasKnowledgeOfHtm0701 }, s) =>\n isYes(hasKnowledgeOfHtm0701, s)\n },\n {\n score: 3,\n response:\n \"The person conducting the audit does not have a working knowledge of HTM 07-01\",\n action:\n \"Familiarise yourself with the Health Technical Memorandum 07-01: Safe management of healthcare waste (HTM 07-01) issued by the Department of Health\",\n autoSelect: ({ hasKnowledgeOfHtm0701 }, s) =>\n isNo(hasKnowledgeOfHtm0701, s)\n },\n {\n score: 3,\n response: \"Details not provided\",\n action:\n \"Familiarise yourself with the Health Technical Memorandum 07-01: Safe management of healthcare waste (HTM 07-01) issued by the Department of Health\",\n autoSelect: ({ hasKnowledgeOfHtm0701 }, s) =>\n isBlank(hasKnowledgeOfHtm0701, s)\n }\n ],\n hasKnowledgeOfEpr507: [\n {\n score: 0,\n response:\n \"The person conducting the audit has working knowledge of EPR 5.07\",\n autoSelect: ({ hasKnowledgeOfEpr507 }, s) =>\n isYes(hasKnowledgeOfEpr507, s)\n },\n {\n score: 3,\n response:\n \"The person conducting the audit does not have a working knowledge of EPR 5.07\",\n action:\n \"Familiarise yourself with the additional guidance for Clinical Waste (EPR 5.07) on how to comply with the environmental permit requirements of your waste disposal company.\",\n autoSelect: ({ hasKnowledgeOfEpr507 }, s) =>\n isNo(hasKnowledgeOfEpr507, s)\n },\n {\n score: 3,\n response: \"Details not provided\",\n action:\n \"Familiarise yourself with the additional guidance for Clinical Waste (EPR 5.07) on how to comply with the environmental permit requirements of your waste disposal company.\",\n autoSelect: ({ hasKnowledgeOfEpr507 }, s) =>\n isBlank(hasKnowledgeOfEpr507, s)\n }\n ],\n fullName: [\n {\n score: 0,\n response: \"Information provided\",\n autoSelect: ({ fullName }, s) => isOnSiteAndPresent(fullName, s)\n },\n {\n score: 0,\n response:\n \"Details not provided, please ensure that the information is provided in full as part of your next audit\",\n autoSelect: ({ fullName }, s) => isBlank(fullName, s)\n },\n {\n score: 0,\n response:\n \"Insufficient details provided, please ensure that the information is provided in full as part of your next audit\"\n }\n ]\n },\n waste_management_policy: {\n policyOwnerName: [\n {\n score: 0,\n response: \"Information provided\",\n autoSelect: ({ policyOwnerName }, s) =>\n isOnSiteAndPresent(policyOwnerName, s)\n },\n {\n score: 0,\n response:\n \"Details not provided, please ensure that the information is provided in full as part of your next audit\",\n autoSelect: ({ policyOwnerName }, s) => isBlank(policyOwnerName, s)\n },\n {\n score: 0,\n response:\n \"Insufficient details provided, please ensure that the information is provided in full as part of your next audit\"\n }\n ],\n policyDocument: [\n {\n score: 0,\n response: \"Policy attached\",\n autoSelect: ({ policyDocument }, s) =>\n isOnSiteAndPresent(policyDocument, s)\n },\n {\n score: 2,\n response:\n \"The attachment is not clearly visible to verify the question, it is therefore not possible to assess whether the requirement has been met. \",\n action:\n \"Refer to the HTM 07-01 issued by the Department of Health and other relevant guidance to set a Waste Management Policy for your practice\"\n },\n {\n score: 2,\n response:\n \"The attachment provided does not correspond to the requirement for this question, It is therefore not possible to assess whether the requirement has been met\",\n action:\n \"Refer to the HTM 07-01 issued by the Department of Health and other relevant guidance to set a Waste Management Policy for your practice\"\n },\n {\n score: 2,\n response:\n \"An attachment has not been provided, it is therefore not possible to assess whether the requirement has been met\",\n action:\n \"Refer to the HTM 07-01 issued by the Department of Health and other relevant guidance to set a Waste Management Policy for your practice\",\n autoSelect: ({ policyDocument }, s) => isBlank(policyDocument, s)\n }\n ],\n hasWasteManagementPolicy: [\n {\n score: 0,\n response: \"Practice has a policy\",\n autoSelect: ({ hasWasteManagementPolicy }, s) =>\n isYes(hasWasteManagementPolicy, s)\n },\n {\n score: 2,\n response:\n \"Practice has no policy, a Waste Management Policy need to be in place for your practice.\",\n action:\n \"Refer to the HTM 07-01 issued by the Department of Health and other relevant guidance to set a Waste Management Policy for your practice\",\n autoSelect: ({ hasWasteManagementPolicy }, s) =>\n isNo(hasWasteManagementPolicy, s)\n },\n {\n score: 2,\n response:\n \"Not Answered, A Waste Management Policy need to be in place for your practice.\",\n action:\n \"Refer to the HTM 07-01 issued by the Department of Health and other relevant guidance to set a Waste Management Policy for your practice\",\n autoSelect: ({ hasWasteManagementPolicy }, s) =>\n isBlank(hasWasteManagementPolicy, s)\n }\n ],\n policyLastReviewDate: [\n {\n score: 0,\n response: \"Date provided less than 1 year old\",\n autoSelect: ({ policyLastReviewDate }, state) =>\n isOnSite(state) && yearsFromSubmit(policyLastReviewDate, state) < 1\n },\n {\n score: 1,\n response: \"Policy is older than 1 Year, your policy is out of date\",\n action:\n \"Review and update your policy. the policy needs to be reviewed and updated every year\",\n autoSelect: ({ policyLastReviewDate }, state) =>\n isOnSite(state) && yearsFromSubmit(policyLastReviewDate, state) >= 1\n },\n {\n score: 0,\n response:\n \"Date provided does not match attachment but is within 1 year\"\n },\n {\n score: 1,\n response:\n \"Date does not match attachment and date on attachment is older than 1 year, your policy is out of date\",\n action:\n \"Review and update your policy. the policy needs to be reviewed and updated every year\"\n },\n {\n score: 1,\n response:\n \"Details not provided, it is therefore not possible to assess whether the requirement has been met\",\n action:\n \"Review and update your policy. The policy needs to be reviewed and updated every year\",\n autoSelect: ({ policyLastReviewDate }, s) =>\n isBlank(policyLastReviewDate, s)\n },\n {\n score: 1,\n response:\n \"No attachment provided. It is therefore not possible to assess whether the date provided matches the relevant policy\",\n action:\n \"Review and update your policy. The policy needs to be reviewed and updated every year\",\n autoSelect: ({ policyDocument }, s) => isBlank(policyDocument, s)\n }\n ]\n },\n waste_management_training: {\n trainingMethod: [\n {\n score: 2,\n response: \"Training is not provided\",\n action:\n \"Ensure that you have suitable training methods in place at your practice\",\n autoSelect: ({ doesWasteManagementTraining }, s) =>\n isNo(doesWasteManagementTraining, s)\n },\n {\n score: 0,\n response: \"Training is provided using suitable methods\",\n autoSelect: ({ trainingMethod }, s) =>\n isPresent(_.compact(Object.values(trainingMethod || {})), s)\n },\n {\n score: 2,\n response: \"No information on your training methods provided\",\n action:\n \"Ensure that you have suitable training methods in place at your practice\",\n autoSelect: ({ trainingMethod }, s) =>\n isBlank(_.compact(Object.values(trainingMethod || {})), s)\n }\n ],\n doesWasteManagementTraining: [\n {\n score: 0,\n response: \"Training provided\",\n autoSelect: ({ doesWasteManagementTraining }, s) =>\n isYes(doesWasteManagementTraining, s)\n },\n {\n score: 2,\n response:\n \"Training is not provided. Your practice is required to deliver Waste Management training to all staff\",\n action:\n \"Setup training material and a training schedule for all your staff. Please refer to the HTM 07-01 issued by the Department of Health for guidance\",\n autoSelect: ({ doesWasteManagementTraining }, s) =>\n isNo(doesWasteManagementTraining, s)\n },\n {\n score: 2,\n response:\n \"No Response. Your practice is required to deliver Waste Management training to all staff\",\n action:\n \"Setup training material and a training schedule for all your staff. Please refer to the HTM 07-01 issued by the Department of Health for guidance\",\n autoSelect: ({ doesWasteManagementTraining }, s) =>\n isBlank(doesWasteManagementTraining, s)\n }\n ],\n hasWasteManagementTrainingRecords: [\n {\n score: 2,\n response: \"Training is not provided\",\n action: \"Ensure that you setup and maintain training records\",\n autoSelect: ({ doesWasteManagementTraining }, s) =>\n isNo(doesWasteManagementTraining, s)\n },\n {\n score: 0,\n response: \"Practice keeps training records\",\n autoSelect: ({ hasWasteManagementTrainingRecords }, s) =>\n isYes(hasWasteManagementTrainingRecords, s)\n },\n {\n score: 2,\n response:\n \"No training records kept. You are required to keep training records of all staff\",\n action: \"Ensure that you setup and maintain training records\",\n autoSelect: ({ hasWasteManagementTrainingRecords }, s) =>\n isNo(hasWasteManagementTrainingRecords, s)\n },\n {\n score: 2,\n response:\n \"No response. You are required to keep training records of all staff\",\n action: \"Ensure that you setup and maintain training records\",\n autoSelect: ({ hasWasteManagementTrainingRecords }, s) =>\n isBlank(hasWasteManagementTrainingRecords, s)\n }\n ],\n whenIsTrainingDone: [\n {\n score: 0,\n response: \"Staff receive induction, ad-hoc and regular training\",\n autoSelect: ({ whenIsTrainingDone }, s) => {\n return (\n whenIsTrainingDone &&\n isPresent(whenIsTrainingDone.regularly, s) &&\n whenIsTrainingDone.atInduction &&\n whenIsTrainingDone.adHoc\n );\n }\n },\n {\n score: 2,\n response: \"Training is not provided\",\n action:\n \"Ensure that training is provided at induction, on a regular basis and ad-hoc if required to all staff\",\n autoSelect: ({ doesWasteManagementTraining }, s) => {\n return isNo(doesWasteManagementTraining, s);\n }\n },\n {\n score: 2,\n response: \"No response provided\",\n action:\n \"Ensure that training is provided at induction, on a regular basis and ad-hoc if required to all staff\",\n autoSelect: ({ whenIsTrainingDone }, s) => {\n return (\n isBlank(whenIsTrainingDone, s) ||\n (!whenIsTrainingDone.atInduction &&\n isBlank(whenIsTrainingDone.regularly, s) &&\n !whenIsTrainingDone.adHoc)\n );\n }\n },\n {\n score: 2,\n response: \"Only induction training provided\",\n action:\n \"Ensure that training is also provided on a regular basis and ad-hoc if required to all staff\",\n autoSelect: ({ whenIsTrainingDone }, s) => {\n return (\n whenIsTrainingDone &&\n whenIsTrainingDone.atInduction &&\n isBlank(whenIsTrainingDone.regularly, s) &&\n !whenIsTrainingDone.adHoc\n );\n }\n },\n {\n score: 0,\n response: \"Staff receive only induction and ad-hoc training\",\n autoSelect: ({ whenIsTrainingDone }, s) => {\n return (\n whenIsTrainingDone &&\n whenIsTrainingDone.atInduction &&\n isBlank(whenIsTrainingDone.regularly, s) &&\n whenIsTrainingDone.adHoc\n );\n }\n },\n {\n score: 0,\n response: \"Staff receive only induction and regular training\",\n autoSelect: ({ whenIsTrainingDone }, s) => {\n return (\n whenIsTrainingDone &&\n isPresent(whenIsTrainingDone.regularly, s) &&\n whenIsTrainingDone.atInduction &&\n !whenIsTrainingDone.adHoc\n );\n }\n },\n {\n score: 2,\n response: \"Induction training not provided\",\n action:\n \"Ensure that induction training is also provided to every new staff member\",\n autoSelect: ({ whenIsTrainingDone }, s) => {\n return whenIsTrainingDone && !whenIsTrainingDone.atInduction;\n }\n }\n ],\n trainingProvidedTo: [\n {\n score: 2,\n response: \"Training is not provided\",\n action:\n \"Setup training material and a training schedule for all your staff\",\n autoSelect: ({ doesWasteManagementTraining }, s) =>\n isNo(doesWasteManagementTraining, s)\n },\n {\n score: 0,\n response: \"Training provided to all staff\",\n autoSelect: ({ trainingProvidedTo }, s) =>\n matchText(trainingProvidedTo, /all staff/i, s)\n },\n {\n score: 1,\n response:\n \"Training is provided to clinical staff only. Your practice is required to deliver Waste Management training to all staff.\",\n action:\n \"Setup training material and a training schedule for all your staff\",\n autoSelect: ({ trainingProvidedTo }, s) =>\n matchText(trainingProvidedTo, /clinical staff only/i, s)\n },\n {\n score: 2,\n response:\n \"No Response. Your practice is required to deliver Waste Management training to all staff.\",\n action:\n \"Setup training material and a training schedule for all your staff\",\n autoSelect: ({ trainingProvidedTo }, s) =>\n isBlank(trainingProvidedTo, s)\n }\n ],\n trainingRecordSample: [\n {\n score: 2,\n response: \"Training is not provided\",\n action:\n \"Ensure that you setup and maintain training records for all staff\",\n autoSelect: ({ doesWasteManagementTraining }, s) =>\n isNo(doesWasteManagementTraining, s)\n },\n {\n score: 0,\n response: \"Sample of training record provided\",\n autoSelect: ({ trainingRecordSample }, s) =>\n isOnSiteAndPresent(trainingRecordSample, s)\n },\n {\n score: 2,\n response:\n \"The attachment is not clearly visible to verify the question. It is therefore not possible to assess whether the requirement has been met\",\n action:\n \"Ensure that you setup and maintain training records for all staff\"\n },\n {\n score: 2,\n response:\n \"The attachment provided does not correspond to the requirement for this question. It is therefore not possible to assess whether the requirement has been met\",\n action:\n \"Ensure that you setup and maintain training records for all staff\"\n },\n {\n score: 2,\n response:\n \"An attachment has not been provided. It is therefore not possible to assess whether the requirement has been met.\",\n action:\n \"Ensure that you setup and maintain training records for all staff\",\n autoSelect: ({ trainingRecordSample }, s) =>\n isBlank(trainingRecordSample, s)\n }\n ],\n hasSegregationSignage: [\n {\n score: 0,\n response: \"Signs are used to outline waste segregation\",\n autoSelect: ({ hasSegregationSignage }, s) =>\n isYes(hasSegregationSignage, s)\n },\n {\n score: 2,\n response: \"Signs are not used to outline waste segregation\",\n action:\n \"To ensure that each staff member understands what bins should be used for which waste type, signs should be placed on or next to each bin providing an overview of what waste types should and should not be placed in that specific bin\",\n autoSelect: ({ hasSegregationSignage }, s) =>\n isNo(hasSegregationSignage, s)\n },\n {\n score: 2,\n response: \"No Response\",\n action:\n \"To ensure that each staff member understands what bins should be used for which waste type, signs should be placed on or next to each bin providing an overview of what waste types should and should not be placed in that specific bin\",\n autoSelect: ({ hasSegregationSignage }, s) =>\n isBlank(hasSegregationSignage, s)\n }\n ]\n },\n hwcn_records: {\n hasHwcnRecords: [\n {\n score: 0,\n response: \"Records of HCWNs are kept\",\n autoSelect: ({ hasHwcnRecords }, s) => isYes(hasHwcnRecords, s)\n },\n {\n score: 2,\n response: \"Records of HWCNs are not kept\",\n action:\n \"The HWCNs may be available in Vector in the 'Documents' section under 'Hazardous Waste Consignment Notes'. If they are not, please raise your request using Anenta's website (https://vector.anenta.com|vector.anenta.com) and click on the blue 'How can we help?’ button on the top right. Historic HWCNs in paper form or HWCNs that pre-date the Anenta NHS agreement should be available at the practice as they would have been left by the waste contractor when collecting the waste or sent to the practice directly.\",\n autoSelect: ({ hasHwcnRecords }, s) => isNo(hasHwcnRecords, s)\n },\n {\n score: 2,\n response: \"No Response\",\n action:\n \"The HWCNs may be available in Vector in the 'Documents' section under 'Hazardous Waste Consignment Notes'. If they are not, please raise your request using Anenta's website (https://vector.anenta.com|vector.anenta.com) and click on the blue 'How can we help?’ button on the top right. Historic HWCNs in paper form or HWCNs that pre-date the Anenta NHS agreement should be available at the practice as they would have been left by the waste contractor when collecting the waste or sent to the practice directly.\",\n autoSelect: ({ hasHwcnRecords }, s) => isBlank(hasHwcnRecords, s)\n }\n ],\n providedByFormat: [\n {\n score: 0,\n response: \"HWCNs provided in electronic format\",\n autoSelect: ({ providedByFormat }, s) =>\n providedByFormat &&\n (providedByFormat.anenta === true ||\n isEmail(providedByFormat.electronic, s))\n },\n {\n score: 0,\n response:\n \"HWCNs provided by e-mail but e-mail address cannot be verified\",\n autoSelect: ({ providedByFormat }, s) =>\n providedByFormat &&\n isPresent(providedByFormat.electronic, s) &&\n !isEmail(providedByFormat.electronic, s)\n },\n {\n score: 0,\n response: \"HWCNs provided in paper format\",\n autoSelect: ({ providedByFormat }, s) =>\n providedByFormat && providedByFormat.paper === true\n },\n {\n score: 2,\n response:\n \"Format of HWCN not provided. HWCNs need to be provided in either paper or electronic format by the waste contractor\",\n action:\n \"Ensure that your practice receives HWCNs with each hazardous waste collection\",\n autoSelect: ({ providedByFormat }, s) =>\n isBlank(_.compact(Object.values(providedByFormat || {})), s)\n }\n ],\n recentHwcnDocumentDate: [\n {\n score: 0,\n response: \"Recent HWCN provided\",\n autoSelect: ({ recentHwcnDocumentDate }, state) =>\n isOnSite(state) &&\n monthsFromSubmit(recentHwcnDocumentDate, state) < 1\n },\n {\n score: 2,\n response:\n \"The date provided is older than 1 month. Your practice should have more recent HWCNs on file\",\n action:\n \"Ensure that your practice stores HWCNs with each hazardous waste collection.\",\n autoSelect: ({ recentHwcnDocumentDate }, state) =>\n isOnSite(state) &&\n monthsFromSubmit(recentHwcnDocumentDate, state) >= 1\n },\n {\n score: 0,\n response:\n \"Date does not match attachment but is less than 1 month old\"\n },\n {\n score: 2,\n response:\n \"The date provided does not match the attached document, the attached document is older than 1 month. Your practice should have more recent HWCNs on file\",\n action:\n \"Ensure that your practice stores HWCNs with each hazardous waste collection.\"\n },\n {\n score: 2,\n response: \"A date has not been provided\",\n action:\n \"Ensure that your practice stores HWCNs with each hazardous waste collection.\",\n autoSelect: ({ recentHwcnDocumentDate }, s) =>\n isBlank(recentHwcnDocumentDate, s)\n },\n {\n score: 2,\n response:\n \"No attachment provided. It is therefore not possible to assess whether the date provided matches the relevant HWCN \",\n action:\n \"Ensure that your practice stores HWCNs with each hazardous waste collection.\",\n autoSelect: ({ recentHwcnDocument }, s) =>\n isBlank(recentHwcnDocument, s)\n }\n ],\n recentHwcnDocument: [\n {\n score: 0,\n response: \"Correct Information attached or clear Image provided\",\n autoSelect: ({ recentHwcnDocument }, s) =>\n isOnSiteAndPresent(recentHwcnDocument, s)\n },\n {\n score: 2,\n response:\n \"No Attachment. An attachment has not been provided. It is therefore not possible to assess whether the requirement has been met\",\n action:\n \"The HWCNs may be available in Vector in the 'Documents' section under 'Hazardous Waste Consignment Notes'. If they are not, please raise your request using Anenta's website (https://vector.anenta.com|vector.anenta.com) and click on the blue 'How can we help?’ button on the top right. Historic HWCNs in paper form or HWCNs that pre-date the Anenta NHS agreement should be available at the practice as they would have been left by the waste contractor when collecting the waste or sent to the practice directly.\",\n autoSelect: ({ recentHwcnDocument }, s) =>\n isBlank(recentHwcnDocument, s)\n },\n {\n score: 2,\n response:\n \"The attachment is not clearly visible to verify the question. It is therefore not possible to assess whether the requirement has been met\",\n action:\n \"The HWCNs may be available in Vector in the 'Documents' section under 'Hazardous Waste Consignment Notes'. If they are not, please raise your request using Anenta's website (https://vector.anenta.com|vector.anenta.com) and click on the blue 'How can we help?’ button on the top right. Historic HWCNs in paper form or HWCNs that pre-date the Anenta NHS agreement should be available at the practice as they would have been left by the waste contractor when collecting the waste or sent to the practice directly.\"\n },\n {\n score: 2,\n response:\n \"Attachment does not match question. The attachment provided does not correspond to the requirement for this question. It is therefore not possible to assess whether the requirement has been met\",\n action:\n \"The HWCNs may be available in Vector in the 'Documents' section under 'Hazardous Waste Consignment Notes'. If they are not, please raise your request using Anenta's website (https://vector.anenta.com|vector.anenta.com) and click on the blue 'How can we help?’ button on the top right. Historic HWCNs in paper form or HWCNs that pre-date the Anenta NHS agreement should be available at the practice as they would have been left by the waste contractor when collecting the waste or sent to the practice directly.\"\n }\n ],\n historicHwcnDocumentDate: [\n {\n score: 0,\n response: \"Date provided 3 years or older\",\n autoSelect: ({ historicHwcnDocumentDate }, state) =>\n isOnSite(state) &&\n yearsFromSubmit(historicHwcnDocumentDate, state) >= 3\n },\n {\n score: 2,\n response: \"Date is less than 3 years old\",\n action:\n \"Ensure that your practice stores HWCNs with each hazardous waste collection\"\n },\n {\n score: 0,\n response:\n \"Date is less than 3 years old but is within a month of practice opening\"\n },\n {\n score: 0,\n response:\n \"Date does not match attachment but is older than 3 years or is within 1 month of practice opening\"\n },\n {\n score: 2,\n response:\n \"The date provided does not match the attached document, the attached document is less than 3 years old, your practice should have more recent HWCNs on file\",\n action:\n \"Ensure that your practice stores HWCNs with each hazardous waste collection\"\n },\n {\n score: 2,\n response:\n \"The date provided does not match the attached document, the attached document is not within 1 month of practice opening, your practice should have more recent HWCNs on file\",\n action:\n \" Ensure that your practice stores HWCNs with each hazardous waste collection.\"\n },\n {\n score: 2,\n response:\n \"No attachment provided. It is therefore not possible to assess whether the date provided matches the relevant HWCN\",\n action:\n \"Ensure that your practice stores HWCNs with each hazardous waste collection\",\n autoSelect: ({ historicHwcnDocument }, s) =>\n isBlank(historicHwcnDocument, s)\n }\n ],\n historicHwcnDocument: [\n {\n score: 0,\n response: \"Correct Information attached or clear Image provided\",\n autoSelect: ({ historicHwcnDocument }, s) =>\n isOnSiteAndPresent(historicHwcnDocument, s)\n },\n {\n score: 2,\n response:\n \"The attachment is not clearly visible to verify the question. It is therefore not possible to assess whether the requirement has been met\",\n action:\n \"The HWCNs may be available in Vector in the 'Documents' section under 'Hazardous Waste Consignment Notes'. If they are not, please raise your request using Anenta's website (https://vector.anenta.com|vector.anenta.com) and click on the blue 'How can we help?’ button on the top right. Historic HWCNs in paper form or HWCNs that pre-date the Anenta NHS agreement should be available at the practice as they would have been left by the waste contractor when collecting the waste or sent to the practice directly.\"\n },\n {\n score: 2,\n response:\n \"Attachment does not match question. The attachment provided does not correspond to the requirement for this question. It is therefore not possible to assess whether the requirement has been met\",\n action:\n \"The HWCNs may be available in Vector in the 'Documents' section under 'Hazardous Waste Consignment Notes'. If they are not, please raise your request using Anenta's website (https://vector.anenta.com|vector.anenta.com) and click on the blue 'How can we help?’ button on the top right. Historic HWCNs in paper form or HWCNs that pre-date the Anenta NHS agreement should be available at the practice as they would have been left by the waste contractor when collecting the waste or sent to the practice directly.\"\n },\n {\n score: 2,\n response:\n \"No Attachment. An attachment has not been provided. It is therefore not possible to assess whether the requirement has been met\",\n action:\n \"The HWCNs may be available in Vector in the 'Documents' section under 'Hazardous Waste Consignment Notes'. If they are not, please raise your request using Anenta's website (https://vector.anenta.com|vector.anenta.com) and click on the blue 'How can we help?’ button on the top right. Historic HWCNs in paper form or HWCNs that pre-date the Anenta NHS agreement should be available at the practice as they would have been left by the waste contractor when collecting the waste or sent to the practice directly.\",\n autoSelect: ({ historicHwcnDocument }, s) =>\n isBlank(historicHwcnDocument, s)\n }\n ]\n },\n internal_waste_containment: {\n bins: internalBinDecisions,\n rooms: roomDecisions\n },\n bulk_waste_storage_containment: {\n bins: externalBinDecisions,\n bulkContainments: bulkContainmentDecisions,\n wasteStreams: wasteStreamDecisions\n }\n }\n};\n\nexport default decisionData;\n\n// export {\n// autoDecide\n// }\n\n//\"clinical\": {\n//\"hasStorage\": [\n//{\n//\"score\": 0,\n//\"response\": \"Site has bulk waste storage for clinical\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"Bulk storage of clinical waste has not been reported\",\n//\"action\": \"Ensure that you have appropriate storage and disposal of Clinical Waste in place for your practice. It is therefore not possible to assess how you dispose clinical waste and if the waste is correctly segregated. Refer to HTM 07-01 issued by the Department of Health and the EPR 5.07 issued by the Environment Agency and other guidelines to setup the appropriate waste disposal for your practice\"\n//}\n//],\n//\"storedSecurely\": [\n//{\n//\"score\": 0,\n//\"response\": \"The clinical waste is stored securely\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"The clinical waste is not stored securely\",\n//\"action\": \"Action\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"No storage reported for clinical waste, storage security cannot be assessed\",\n//\"action\": \"Action\"\n//}\n//],\n//\"packagedCorrectly\": [\n//{\n//\"score\": 0,\n//\"response\": \"Waste is packaged in approved containers\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"Waste not packaged in approved containers\",\n//\"action\": \"Ensure that your clinical waste is correctly packaged. Refer to HTM 07-01 issued by the Department of Health and the EPR 5.07 issued by the Environment Agency and other guidelines to setup the appropriate waste disposal for your practice\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"No storage reported for clinical waste, packaging cannot be assessed\",\n//\"action\": \"Ensure that your clinical waste is correctly packaged. It is therefore not possible to assess how you dispose clinical waste and if the waste is correctly packaged. Refer to HTM 07-01 issued by the Department of Health and the EPR 5.07 issued by the Environment Agency and other guidelines to setup the appropriate waste disposal for your practice\"\n//}\n//],\n//\"contaminationFound\": [\n//{\n//\"score\": 0,\n//\"response\": \"No contamination\"\n//},\n//{\n//\"score\": 2,\n//\"response\": \"Contaminated with non clinical waste\",\n//\"action\": \"Ensure that the appropriate waste segregation is in place and that bins / areas are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin / area outlining segregation requirement by waste type (What waste type should go in what bin type / area and what waste type not)\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"There is no storage reported for clinical waste, Contamination cannot be assessed\",\n//\"action\": \"Ensure that the appropriate waste segregation is in place and that bins / areas are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin / area outlining segregation requirement by waste type (What waste type should go in what bin type / area and what waste type not)\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"There is insufficient information provided and contamination cannot be assessed\",\n//\"action\": \"Ensure that the appropriate waste segregation is in place and that bins / areas are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin / area outlining segregation requirement by waste type (What waste type should go in what bin type / area and what waste type not)\"\n//},\n//]\n//},\n//\"general\": {\n//\"hasStorage\": [\n//{\n//\"score\": 0,\n//\"response\": \"Site has bulk waste storage for general\",\n//\"autoSelect\": ({hasStorage, ...x}, s) => {\n//return isPresent(_.get(hasStorage, 'clearlyIdentified'), )\n//}\n//},\n//{\n//\"score\": 3,\n//\"response\": \"Bulk storage of general waste has not been reported\",\n//\"action\": \"Ensure that you have appropriate storage and disposal of general Waste in place for your practice. It is therefore not possible to assess how you dispose general waste and if the waste is correctly segregated. Refer to HTM 07-01 issued by the Department of Health and the EPR 5.07 issued by the Environment Agency and other guidelines to setup the appropriate waste disposal for your practice\",\n//\"autoSelect\": ({hasClinicalBins, ...x}, s) => {\n//return hasStorage && isBlank(_.get(hasStorage, 'clearlyIdentified'))\n//}\n//}\n//],\n//\"packagedCorrectly\": [\n//{\n//\"score\": 0,\n//\"response\": \"Waste is packaged in approved containers\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"Waste not packaged in approved containers\",\n//\"action\": \"Ensure that your general waste is correctly packaged. Refer to HTM 07-01 issued by the Department of Health and the EPR 5.07 issued by the Environment Agency and other guidelines to setup the appropriate waste disposal for your practice\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"No storage reported for general waste, packaging cannot be assessed\",\n//\"action\": \"Ensure that your general waste is correctly packaged. It is therefore not possible to assess how you dispose general waste and if the waste is correctly packaged. Refer to HTM 07-01 issued by the Department of Health and the EPR 5.07 issued by the Environment Agency and other guidelines to setup the appropriate waste disposal for your practice\"\n//}\n//],\n//\"contaminationFound\": [\n//{\n//\"score\": 0,\n//\"response\": \"No contamination\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"Contaminated with clinical waste\",\n//\"action\": \"Ensure that the appropriate waste segregation is in place and that bins / areas are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin / area outlining segregation requirement by waste type (What waste type should go in what bin type / area and what waste type not)\"\n//},\n//{\n//\"score\": 2,\n//\"response\": \"There is no storage reported for general waste, Contamination cannot be assessed\",\n//\"action\": \"Ensure that the appropriate waste segregation is in place and that bins / areas are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin / area outlining segregation requirement by waste type (What waste type should go in what bin type / area and what waste type not)\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"There is insufficient information provided contamination cannot be assessed\",\n//\"action\": \"Ensure that the appropriate waste segregation is in place and that bins / areas are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin / area outlining segregation requirement by waste type (What waste type should go in what bin type / area and what waste type not)\"\n//},\n//]\n//},\n//\"recycling\": {\n//\"hasStorage\": [\n//{\n//\"score\": 0,\n//\"response\": \"Site has bulk waste storage for recycling\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"Bulk storage of recycling waste has not been reported\",\n//\"action\": \"Ensure that you have appropriate storage and disposal of recycling Waste in place for your practice. It is therefore not possible to assess how you dispose recycling waste and if the waste is correctly segregated. Refer to HTM 07-01 issued by the Department of Health and the EPR 5.07 issued by the Environment Agency and other guidelines to setup the appropriate waste disposal for your practice\"\n//}\n//],\n//\"contaminationFound\": [\n//{\n//\"score\": 0,\n//\"response\": \"No contamination\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"Contaminated with clinical waste\",\n//\"action\": \"Ensure that the appropriate waste segregation is in place and that bins / areas are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin / area outlining segregation requirement by waste type (What waste type should go in what bin type / area and what waste type not)\"\n//},\n//{\n//\"score\": 2,\n//\"response\": \"There is no storage reported for recycling waste, Contamination cannot be assessed\",\n//\"action\": \"Ensure that the appropriate waste segregation is in place and that bins / areas are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin / area outlining segregation requirement by waste type (What waste type should go in what bin type / area and what waste type not)\"\n//},\n//{\n//\"score\": 3,\n//\"response\": \"There is insufficient information provided contamination cannot be assessed\",\n//\"action\": \"Ensure that the appropriate waste segregation is in place and that bins / areas are available and used for each waste stream. Reiterate training on waste handling and segregation. Add, change or re-position posters at each bin / area outlining segregation requirement by waste type (What waste type should go in what bin type / area and what waste type not)\"\n//},\n//]\n//},\n","import _ from 'lodashExtended'\nimport decisionData from './decisionData'\nimport { getRequiredRoomCount, getBulkStorageTypes } from \"../../auditor/app/selectors\";\n\n\nconst getCurrentUser = (state) => {\n return state.app.currentUser\n}\n\nconst getAuditType = (state) => {\n return state.app.auditType\n}\n\nconst sumReviewResults = (reviewResults) => {\n const maxScore = _(reviewResults).map('maxScore').compact().sum()\n const score = _(reviewResults).map('score').compact().sum()\n const actionItems = _(reviewResults).map('actionItems').flatten().value()\n\n return {\n maxScore,\n score,\n actionItems\n }\n}\n\nconst scoreToTimeline = {\n 3: 'immediate',\n 2: '2_weeks',\n 1: '1_month',\n 0: '3_months',\n}\n\nconst mapReviewResult = (requiredFields, reviewData, actionSection) => {\n const requiredFieldNames = Object.keys(_.pickBy(requiredFields))\n\n const maxScore = _(requiredFieldNames).map((fieldName) => _.get(reviewData, `${fieldName}.maxScore`) ).compact().sum()\n const score = _(requiredFieldNames).map((fieldName) => _.get(reviewData, `${fieldName}.score`) ).compact().sum()\n const actionItems = _(requiredFieldNames).map((fieldName) => { \n const suggestedAction = _.get(reviewData, `${fieldName}.action`)\n if(_.isPresent(suggestedAction)) {\n const timeline = scoreToTimeline[_.get(reviewData, `${fieldName}.score`)]\n const observation = _.get(reviewData, `${fieldName}.response`)\n\n return {\n timeline,\n observation,\n suggestedAction,\n actionSection\n }\n }\n }).compact().value()\n\n return {\n maxScore,\n score,\n actionItems\n }\n\n}\n\nconst getSubmissionDate = (state) => {\n return _.get(state, 'app.submittedOn')\n}\n\n\nconst checkAllDataLoaded = (state) => {\n return _.difference([\n 'waste_audits',\n 'sections',\n 'sectionReviews',\n 'bins',\n 'binReviews',\n 'rooms',\n 'roomReviews',\n 'bulkContainments',\n 'bulkContainmentReviews',\n 'wasteStreamReviews'\n ], Object.keys(state.firestore.data)).length === 0\n}\n\nconst getDecisionData = (state) => decisionData\n\nconst makeObservation = (decision, allOptions, state) => {\n return {\n action: null,\n ..._.pick(decision, ['action', 'score', 'response']),\n maxScore: _(allOptions).map('score').max()\n }\n}\n\nconst hasObservation = (object, fieldName) => {\n return !_.isNil(_.get(object, `reviewData.${fieldName}.score`)) && !_.isNil(_.get(object, `reviewData.${fieldName}.response`))\n}\n\nconst makeNoScoreObservation = (decision, allOptions, state) => {\n return {\n ..._.pick(decision, ['result', 'response'])\n }\n}\n\nconst getObservationResult = (object, fieldName) => {\n return _.get(object, `reviewData.${fieldName}.result`)\n}\n\nconst hasNoScoreObservation = (object, fieldName) => {\n return !_.isNil(getObservationResult(object, fieldName)) && !_.isNil(_.get(object, `reviewData.${fieldName}.response`))\n}\n\nconst autoReviewData = (inputData, requiredFields, savedReviewData, decisionData, getObservation, state) => {\n var reviewData = {}\n var autoReviewData = {}\n const requiredFieldNames = _(requiredFields).pickBy((required,field) => required ).keys().value()\n\n _.each(requiredFieldNames, (field) => {\n var allOptions = decisionData[field]\n\n var autoDecision = _.find(allOptions, ({response, autoSelect}) => {\n return autoSelect && autoSelect(inputData, state) }\n )\n\n if(autoDecision) {\n autoReviewData[field] = getObservation(autoDecision, allOptions, state)\n }\n\n reviewData[field] = {\n ...(autoReviewData[field] || {}),\n ...(savedReviewData[field] || {})\n }\n })\n\n return {\n ..._.omit(savedReviewData, requiredFieldNames),\n ...reviewData,\n }\n}\n\nconst getRequiredWasteStreamIds = (state) => {\n return _(getBulkStorageTypes(state)).filter('auditRequired').map('id').value()\n}\n\n\nexport {\n getCurrentUser,\n getAuditType,\n checkAllDataLoaded,\n getDecisionData,\n makeNoScoreObservation,\n hasNoScoreObservation,\n getObservationResult,\n makeObservation,\n hasObservation,\n autoReviewData,\n mapReviewResult,\n sumReviewResults,\n getSubmissionDate,\n getRequiredRoomCount,\n getRequiredWasteStreamIds\n}\n","import React, { useEffect } from \"react\";\nimport PropTypes from \"prop-types\";\n//import { connect } from \"react-redux\";\nimport _ from \"lodashExtended\";\nimport { useLocation } from \"react-router-dom\";\n\nvar SectionReview = ({\n title,\n sectionId,\n children,\n}) => {\n\n const { pathname } = useLocation();\n\n useEffect(() => {\n window.scrollTo(0, 0);\n }, [pathname]);\n\n\n return (\n \n );\n};\n\nSectionReview.propTypes = {\n title: PropTypes.node.isRequired,\n children: PropTypes.node.isRequired,\n sectionId: PropTypes.string.isRequired,\n};\n\n//const mapStateToProps = (state, { sectionId }) => {\n //return {\n //sectionStatus: getSectionStatus(sectionId, state),\n //incompleteMessage: getIncompleteMessage(sectionId, state)\n //};\n//};\n\n//const mapDispatchToProps = (dispatch, { sectionId, ...rest }) => {\n //return {\n //onSubmit: () => { dispatch(submitSection(sectionId)) },\n //onNavigateFrom: (navigateFromSectionId) => { dispatch(navigateFromSection(navigateFromSectionId))},\n //};\n//};\n\n//Section = connect(mapStateToProps, mapDispatchToProps)(Section);\n\nexport default SectionReview;\n\n","import React, { useState } from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { TextAreaInput, Btn } from 'sharedComponents'\nimport { faTrash, faEdit, faTrashAlt } from \"@fortawesome/free-solid-svg-icons\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\n//import { connect } from 'react-redux';\n//import classNames from \"classnames\";\n//import actions from '../slice/actions'\n//var {\n//} = actions\n\nvar Comment = ( {\n text,\n onChange\n} ) => {\n\n const [editMode, setEditMode ] = useState(false)\n\n if(editMode) {\n return(\n \n onChange(value) }\n />\n setEditMode(false) }>Done \n
\n )\n } else {\n if(_.isBlank(text)) {\n return(\n setEditMode(true) }\n >\n + Add Comment \n
\n )\n } else {\n return(\n \n \n \n setEditMode(true)}\n />\n \n \n onChange(null)}\n />\n \n \n {text}\n
\n )\n }\n }\n}\n\nComment.propTypes = {\n text: PropTypes.string,\n onChange: PropTypes.func.isRequired,\n};\n\nexport default Comment;\n\n\n\n\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { Alert } from 'react-bootstrap'\nimport ErrorOutlineIcon from '@material-ui/icons/ErrorOutline';\n\n//import classNames from \"classnames\";\n//import { DropdownSelect, DateSelect, ModelErrors, Link } from 'sharedComponents'\n//import actions from '../slice/actions'\n//var {\n//} = actions\n\nvar Action = ( { text } ) => {\n\n if(_.isPresent(text)) {\n return(\n \n
Action Item
\n
{text}
\n
\n )\n } else {\n return null\n }\n\n}\n\n//class Action extends React.Component {\n\n //constructor(props) {\n //super(props);\n //this.state = { minimized: true }\n //this.handleToggleMinimized = this.handleToggleMinimized.bind(this)\n //}\n\n //handleToggleMinimized() {\n //this.setState({minimized: !this.state.minimized})\n //}\n\n //render() {\n //const { } = this.props\n //const { minimized } = this.state\n\n //const content = minimized ? null : {\"Action\"}
\n\n //return (\n //\n //\n // \n // \n //{ content }\n //
\n //)\n //}\n//}\n\n\n//Action.propTypes = {\n//};\n\n\n//const mapStateToProps = (state, {}) => {\n //return {\n //}\n//}\n\n//const mapDispatchToProps = (dispatch, {}) => {\n //return {\n //}\n//}\n\n//Action = connect(\n //mapStateToProps,\n //mapDispatchToProps\n//)(Action)\n\n\nexport default Action;\n\n\n\n\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport DoneIcon from '@material-ui/icons/Done';\nimport ErrorIcon from '@material-ui/icons/Error';\n\nvar CompleteStatusIcon = ( { isComplete, className = '' } ) => {\n\n var statusIcon = isComplete ?\n \n : \n\n return(statusIcon)\n}\n\nexport default CompleteStatusIcon;\n\n\n\n\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { Badge, Panel } from 'react-bootstrap';\nimport { RadioInput } from \"sharedComponents\";\nimport Comment from \"./Comment\";\nimport Action from \"./Action\";\nimport CompleteStatusIcon from \"./CompleteStatusIcon\";\nimport { Alert } from 'react-bootstrap'\nimport { faExclamationCircle } from \"@fortawesome/free-solid-svg-icons\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { scoreToClass, scoreToRiskLevel } from '../wasteAudit/selectors'\n\nvar QuestionReview = ({\n fieldName,\n value,\n children,\n label,\n reviewData,\n decisionData,\n onDecision,\n onCommentChange,\n}) => {\n\n var {\n score,\n response,\n comment,\n action,\n maxScore\n } = reviewData[fieldName] || {}\n\n const decisionOptions = decisionData[fieldName]\n const radioOptions = _.map(decisionOptions, (decision) => ({ value: decision.response, label: decision.response, decision }) )\n\n var defaultValue = value || children || (\n \n {\" \"}\n Not Answered\n \n );\n\n var isComplete = _.isPresent(response) && _.isPresent(score)\n\n return(\n \n
\n
\n
{label}
\n
\n { _.isPresent(score) ? `${score} / ${maxScore}` : null }\n
\n
\n
\n
\n
\n
\n
\n { onDecision(_.find(decisionOptions,{response}), fieldName, decisionOptions) }}\n />\n
\n
\n
\n {\n onCommentChange(comment, fieldName)\n }}\n />\n
\n
\n
\n
\n
\n\n )\n}\n\n\nQuestionReview.propTypes = {\n fieldName: PropTypes.string.isRequired,\n decisionData: PropTypes.object.isRequired,\n reviewData: PropTypes.object.isRequired,\n onDecision: PropTypes.func.isRequired,\n onCommentChange: PropTypes.func.isRequired,\n};\n\n\n//const mapStateToProps = (state, {}) => {\n //return {\n //}\n//}\n\n//const mapDispatchToProps = (dispatch, {}) => {\n //return {\n //}\n//}\n\n//QuestionReview = connect(\n //mapStateToProps,\n //mapDispatchToProps\n//)(QuestionReview)\n\n\nexport default QuestionReview;\n\n\n\n\n\n\n","import { makeObservation } from '../app/selectors'\n\nconst makeQuestionObservation = (sectionId, fieldName, decision, allOptions) => (dispatch, getState) => {\n\n var args = {\n [fieldName]: makeObservation(decision, allOptions, getState())\n }\n\n dispatch(updateSectionReviewData(sectionId, args))\n\n}\n\nconst makeQuestionComment = (sectionId, fieldName, comment) => (dispatch, getState) => {\n\n var args = {\n [fieldName]: {\n comment\n }\n }\n\n dispatch(updateSectionReviewData(sectionId, args))\n\n}\n\nconst updateSectionReviewData = (sectionId, args) => (dispatch, getState, { getFirebase, getFirestore}) => {\n const state = getState()\n const firestore = getFirestore()\n\n firestore.set(\n {\n collection: 'waste_audits',\n doc: state.app.wasteAuditDocumentId,\n subcollections: [{ collection: 'sectionReviews', doc: sectionId }],\n },\n args,\n { merge: true }\n ).then(() => {\n dispatch({ type: 'UPDATE SUCCESS' });\n }).catch(err => {\n dispatch({ type: 'UPDATE ERROR' }, err);\n });\n\n}\n\nexport {\n makeQuestionObservation,\n makeQuestionComment\n}\n\n","import React, { useReducer } from \"react\";\nimport PropTypes from \"prop-types\";\nimport { compose } from \"redux\";\nimport { connect } from \"react-redux\";\nimport _ from \"lodashExtended\";\nimport dotProp from \"dot-prop-immutable\";\nimport SectionReview from \"../SectionReview\";\nimport QuestionReview from \"../QuestionReview\";\nimport { mapReviewResult } from '../../app/selectors'\nimport { makeQuestionObservation, makeQuestionComment } from '../../sectionReviews/operations'\n\nconst SECTION_ID = \"general_information\";\nconst TITLE = \"General Information\";\n\nconst d = dotProp;\n\nconst getRequiredFields = () => {\n\n var requiredFields = {\n fullName: true,\n jobTitle: true,\n email: true,\n hasKnowledgeOfEpr507: true,\n hasKnowledgeOfHtm0701: true\n }\n\n return requiredFields\n}\n\n\nconst getReviewResult = (sectionData) => {\n const { title, reviewData, number } = sectionData\n return mapReviewResult(getRequiredFields(sectionData), reviewData, `${number} - ${title}`)\n}\n\nconst ViewOnlyField = ( {\n label,\n value,\n} ) => {\n return(\n \n )\n}\n\n\nvar GeneralInformation = ({\n onDecision,\n onCommentChange,\n decisionData,\n sectionData,\n ...rest\n} ) => {\n\n const {\n fullName,\n jobTitle,\n email,\n hasKnowledgeOfHtm0701,\n hasKnowledgeOfEpr507,\n clinicalEmployeeCount,\n clinicallyActiveRoomsCount,\n location,\n reviewData\n } = sectionData;\n\n const questionReviewProps = {\n onDecision,\n reviewData,\n decisionData,\n onCommentChange\n }\n\n return (\n \n \n
\n
\n Practice general information\n
\n
\n
\n
\n
\n
\n Person conducting the Waste Management Audit\n
\n
\n
\n
\n
\n
\n
\n\n
\n \n );\n};\n\nGeneralInformation.propTypes = {};\n\nconst mapStateToProps = (state, { wasteAudit }) => {\n return state\n};\n\nconst mapDispatchToProps = (dispatch, { }) => {\n return {\n onDecision: (decision, fieldName, decisionOptions) => {\n dispatch(makeQuestionObservation(SECTION_ID, fieldName, decision, decisionOptions ));\n },\n onCommentChange: (comment, fieldName) => {\n dispatch(makeQuestionComment(SECTION_ID, fieldName, comment ));\n },\n };\n};\n\nGeneralInformation = connect(\n mapStateToProps,\n mapDispatchToProps\n)(GeneralInformation);\n\n//export default GeneralInformation;\n\nexport default {\n sectionId: SECTION_ID,\n title: TITLE,\n getReviewResult,\n getRequiredFields,\n Component: GeneralInformation,\n}\n\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\n//import { connect } from 'react-redux';\n//import classNames from \"classnames\";\nimport { Link } from 'sharedComponents'\n//var {\n//} = actions\n\nfunction truncateFilename(n, len) {\n var ext = n.substring(n.lastIndexOf(\".\") + 1, n.length).toLowerCase();\n var filename = n.replace(\".\" + ext, \"\");\n if (filename.length <= len) {\n return n;\n }\n filename = filename.substr(0, len) + (n.length > len ? \"[...]\" : \"\");\n return filename + \".\" + ext;\n}\n\nvar DocumentView = ( { fieldName, document } ) => {\n\n return(\n \n \n {truncateFilename(document.metadata.name, 25)}\n \n
\n )\n\n}\n\n//class DocumentView extends React.Component {\n\n //constructor(props) {\n //super(props);\n //this.state = { minimized: true }\n //this.handleToggleMinimized = this.handleToggleMinimized.bind(this)\n //}\n\n //handleToggleMinimized() {\n //this.setState({minimized: !this.state.minimized})\n //}\n\n //render() {\n //const { } = this.props\n //const { minimized } = this.state\n\n //const content = minimized ? null : {\"DocumentView\"}
\n\n //return (\n //\n //\n // \n // \n //{ content }\n //
\n //)\n //}\n//}\n\n\nDocumentView.propTypes = {\nfieldName: PropTypes.string.isRequired\n};\n\n\n//const mapStateToProps = (state, {}) => {\n //return {\n //}\n//}\n\n//const mapDispatchToProps = (dispatch, {}) => {\n //return {\n //}\n//}\n\n//DocumentView = connect(\n //mapStateToProps,\n //mapDispatchToProps\n//)(DocumentView)\n\n\nexport default DocumentView;\n\n\n\n\n\n\n","import React, { useReducer } from \"react\";\nimport PropTypes from \"prop-types\";\nimport { compose } from \"redux\";\nimport { connect } from \"react-redux\";\nimport _ from \"lodashExtended\";\nimport dotProp from \"dot-prop-immutable\";\nimport SectionReview from \"../SectionReview\";\nimport QuestionReview from \"../QuestionReview\";\nimport DocumentView from \"../DocumentView\";\nimport { mapReviewResult, getSubmissionDate } from '../../app/selectors'\nimport moment from 'moment.distance'\n\n\nimport {\n makeQuestionObservation,\n makeQuestionComment\n} from '../../sectionReviews/operations'\n\nconst SECTION_ID = \"waste_management_policy\";\nconst TITLE = \"Waste Management Policy\";\n\nconst d = dotProp;\n\nconst getRequiredFields = () => {\n\n var requiredFields = {\n hasWasteManagementPolicy: true,\n policyDocument: true,\n policyOwnerName: true,\n policyLastReviewDate: true,\n }\n\n return requiredFields\n}\n\nconst getReviewResult = (sectionData) => {\n const { title, reviewData, number } = sectionData\n return mapReviewResult(getRequiredFields(sectionData), reviewData, `${number} - ${title}`)\n}\n\nvar WasteManagementPolicy = ({\n onDecision,\n onCommentChange,\n decisionData,\n submittedOn,\n sectionData,\n ...rest\n} ) => {\n\n const {\n hasWasteManagementPolicy,\n policyDocument,\n policyOwnerName,\n policyLastReviewDate,\n reviewData,\n } = sectionData;\n\n const questionReviewProps = {\n onDecision,\n reviewData,\n decisionData,\n onCommentChange\n }\n\n return (\n \n \n
\n
\n
\n { policyDocument && }\n \n
\n
\n {\n policyLastReviewDate ? \n { moment(policyLastReviewDate).format(\"DD/MM/YYYY\")}
\n \n {moment.duration(moment(submittedOn).diff(moment(policyLastReviewDate))).distance({includeSeconds: false})} prior to submission\n
\n : null\n }\n \n
\n
\n \n );\n};\n\nWasteManagementPolicy.propTypes = {};\n\nconst mapStateToProps = (state, { wasteAudit }) => {\n return {\n submittedOn: getSubmissionDate(state)\n }\n};\n\nconst mapDispatchToProps = (dispatch, { }) => {\n return {\n onDecision: (decision, fieldName, decisionOptions) => {\n dispatch(makeQuestionObservation(SECTION_ID, fieldName, decision, decisionOptions ));\n },\n onCommentChange: (comment, fieldName) => {\n dispatch(makeQuestionComment(SECTION_ID, fieldName, comment ));\n },\n };\n};\n\nWasteManagementPolicy = connect(\n mapStateToProps,\n mapDispatchToProps\n)(WasteManagementPolicy);\n\n//export default GeneralInformation;\n\nexport default {\n sectionId: SECTION_ID,\n title: TITLE,\n getReviewResult,\n getRequiredFields,\n Component: WasteManagementPolicy,\n}\n\n\n\n","import React, { useReducer } from \"react\";\nimport PropTypes from \"prop-types\";\nimport { compose } from \"redux\";\nimport { connect } from \"react-redux\";\nimport _ from \"lodashExtended\";\nimport dotProp from \"dot-prop-immutable\";\nimport SectionReview from \"../SectionReview\";\nimport QuestionReview from \"../QuestionReview\";\nimport { Link } from \"sharedComponents\";\nimport DocumentView from \"../DocumentView\";\nimport { mapReviewResult } from '../../app/selectors'\n\nimport {\n makeQuestionObservation,\n makeQuestionComment\n} from '../../sectionReviews/operations'\n\nconst SECTION_ID = \"waste_management_training\";\nconst TITLE = \"Waste Management Training\";\n\nconst d = dotProp;\n\nconst getRequiredFields = () => {\n\n var requiredFields = {\n doesWasteManagementTraining: true,\n hasWasteManagementTrainingRecords: true,\n trainingProvidedTo: true,\n trainingRecordSample: true,\n whenIsTrainingDone: true,\n hasSegregationSignage: true,\n trainingMethod: true,\n }\n\n return requiredFields\n}\n\nconst getReviewResult = (sectionData) => {\n const { title, reviewData, number } = sectionData\n return mapReviewResult(getRequiredFields(sectionData), reviewData, `${number} - ${title}`)\n}\n\nconst getDisplayText = (value, trueText) => {\n return value ? `${trueText}${value !== true ? `, ${value}` : \"\"}` : null;\n};\n\nvar WasteManagementTraining = ({\n onDecision,\n onCommentChange,\n decisionData,\n sectionData,\n ...rest\n} ) => {\n\n const {\n doesWasteManagementTraining,\n hasWasteManagementTrainingRecords,\n trainingProvidedTo,\n trainingRecordSample,\n whenIsTrainingDone,\n hasSegregationSignage,\n trainingMethod,\n reviewData,\n } = sectionData;\n\n const { atInduction, adHoc, regularly } = whenIsTrainingDone || {};\n const { online, group, onToOne } = trainingMethod || {};\n\n const questionReviewProps = {\n onDecision,\n reviewData,\n decisionData,\n onCommentChange\n }\n\n return (\n \n \n
\n
\n
\n
\n {\n atInduction || adHoc || regularly ? \n [\n [atInduction, \"At Induction\"],\n [adHoc, \"Ad Hoc\"],\n [regularly, \"Regularly\"],\n ].map((x, index) => (\n {getDisplayText(...x)}
\n )) : null\n }\n \n
\n {\n online || group || onToOne ? [\n [online, \"Online\"],\n [group, \"Group\"],\n [onToOne, \"One to one\"],\n ].map((x, index) => (\n {getDisplayText(...x)}
\n )) : null }\n \n
\n
\n { trainingRecordSample && }\n\n \n
\n
\n
\n \n );\n};\n\nWasteManagementTraining.propTypes = {};\n\nconst mapStateToProps = (state, { wasteAudit }) => {\n return state\n};\n\nconst mapDispatchToProps = (dispatch, { }) => {\n return {\n onDecision: (decision, fieldName, decisionOptions) => {\n dispatch(makeQuestionObservation(SECTION_ID, fieldName, decision, decisionOptions ));\n },\n onCommentChange: (comment, fieldName) => {\n dispatch(makeQuestionComment(SECTION_ID, fieldName, comment ));\n },\n };\n};\n\nWasteManagementTraining = connect(\n mapStateToProps,\n mapDispatchToProps\n)(WasteManagementTraining);\n\n//export default GeneralInformation;\n\nexport default {\n sectionId: SECTION_ID,\n title: TITLE,\n getReviewResult,\n getRequiredFields,\n Component: WasteManagementTraining,\n}\n\n\n\n","import React, { useReducer } from \"react\";\nimport PropTypes from \"prop-types\";\nimport { compose } from \"redux\";\nimport { connect } from \"react-redux\";\nimport _ from \"lodashExtended\";\nimport dotProp from \"dot-prop-immutable\";\nimport moment from 'moment.distance'\nimport SectionReview from \"../SectionReview\";\nimport QuestionReview from \"../QuestionReview\";\nimport DocumentView from \"../DocumentView\";\nimport { mapReviewResult, getSubmissionDate } from '../../app/selectors'\n\nimport {\n makeQuestionObservation,\n makeQuestionComment\n} from '../../sectionReviews/operations'\n\nconst SECTION_ID = \"hwcn_records\";\nconst TITLE = \"Hazardous Waste Consignment Notes\";\n\nconst d = dotProp;\n\nconst getRequiredFields = () => {\n\n var requiredFields = {\n hasHwcnRecords: true,\n providedByFormat: true,\n recentHwcnDocument: true,\n recentHwcnDocumentDate: true,\n historicHwcnDocument: true,\n historicHwcnDocumentDate: true\n }\n\n return requiredFields\n}\n\nconst getReviewResult = (sectionData) => {\n const { title, reviewData, number } = sectionData\n return mapReviewResult(getRequiredFields(sectionData), reviewData, `${number} - ${title}`)\n}\n\nconst getDisplayText = (value, trueText) => {\n return value ? `${trueText}${value !== true ? `, ${value}` : \"\"}` : null;\n};\n\nvar HazardousWasteConsignmentNotes = ({\n onDecision,\n onCommentChange,\n decisionData,\n sectionData,\n submittedOn,\n ...rest\n} ) => {\n\n const {\n hasHwcnRecords,\n has3YearsHwcnRecords,\n recentHwcnDocument,\n historicHwcnDocument,\n recentHwcnDocumentDate,\n historicHwcnDocumentDate,\n reviewData,\n providedByFormat = {},\n } = sectionData;\n\n const { paper, electronic, anenta } = providedByFormat;\n\n\n const questionReviewProps = {\n onDecision,\n reviewData,\n decisionData,\n onCommentChange\n }\n\n\n\n var m = moment\n\n return (\n \n \n
\n\n
\n\n
\n {[\n [paper, \"Paper\"],\n [electronic, \"Electronic\", \"sent to \"],\n [anenta, \"Online via Anenta\"],\n ].map((x, index) => (\n {getDisplayText(...x)}
\n ))}\n \n\n
\n { recentHwcnDocument && }\n \n\n
\n {\n recentHwcnDocumentDate ? \n { moment(recentHwcnDocumentDate).format(\"DD/MM/YYYY\")}
\n \n {moment.duration(moment(submittedOn).diff(moment(recentHwcnDocumentDate))).distance({includeSeconds: false})} prior to submission\n
\n : null\n }\n \n\n
\n { historicHwcnDocument && }\n \n\n
\n {\n historicHwcnDocumentDate ? \n { moment(historicHwcnDocumentDate).format(\"DD/MM/YYYY\")}
\n \n {moment.duration(moment(submittedOn).diff(moment(historicHwcnDocumentDate))).distance({includeSeconds: false})} prior to submission\n
\n : null\n }\n \n
\n
\n \n );\n};\n\nHazardousWasteConsignmentNotes.propTypes = {};\n\nconst mapStateToProps = (state, { wasteAudit }) => {\n return {\n submittedOn: getSubmissionDate(state)\n }\n};\n\nconst mapDispatchToProps = (dispatch, { }) => {\n return {\n onDecision: (decision, fieldName, decisionOptions) => {\n dispatch(makeQuestionObservation(SECTION_ID, fieldName, decision, decisionOptions ));\n },\n onCommentChange: (comment, fieldName) => {\n dispatch(makeQuestionComment(SECTION_ID, fieldName, comment ));\n },\n };\n};\n\nHazardousWasteConsignmentNotes = connect(\n mapStateToProps,\n mapDispatchToProps\n)(HazardousWasteConsignmentNotes);\n\n//export default GeneralInformation;\n\nexport default {\n sectionId: SECTION_ID,\n title: TITLE,\n getReviewResult,\n getRequiredFields,\n Component: HazardousWasteConsignmentNotes,\n}\n\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\n//import { connect } from 'react-redux';\n//import classNames from \"classnames\";\n//import { DropdownSelect, DateSelect, ModelErrors, Link } from 'sharedComponents'\n//import actions from '../slice/actions'\n//var {\n//} = actions\nconst MISSING_BIN_IMAGE_URL = \"https://res.cloudinary.com/anenta-ltd/image/upload/v1598996270/waste_audit_examples/200x200_bin_placeholder.png\"\n\nvar ImageView = ( {\n version,\n image,\n className,\n link,\n blankSrc = MISSING_BIN_IMAGE_URL\n} ) => {\n\n var imageUrl = version ? _.get(image, `otherVersions.${version}.url`) : _.get(image, `url`)\n\n\n return(\n \n {\n imageUrl ?\n
\n \n :\n
\n }\n
\n )\n}\n\n\nImageView.propTypes = {\n version: PropTypes.string,\n image: PropTypes.object,\n};\n\n\n\nexport default ImageView;\n\n\n\n\n\n\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport _ from \"lodashExtended\";\nimport { faBan } from \"@fortawesome/free-solid-svg-icons\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\n\nconst BinField = ({\n label,\n value\n}) => {\n\n var renderValue = _.isPresent(value) ? (\n value\n ) : (\n \n Not Answered\n \n )\n\n return (\n \n {label} : {renderValue}\n
\n );\n};\n\n\nBinField.propTypes = {\n label: PropTypes.node.isRequired,\n value: PropTypes.node,\n};\n\nexport default BinField;\n","import { makeNoScoreObservation } from '../app/selectors'\n\nconst makeQuestionObservation = (binId, fieldName, decision, allOptions) => (dispatch, getState) => {\n var args = {\n [fieldName]: makeNoScoreObservation(decision, allOptions, getState())\n }\n\n dispatch(updateBinReviewData(binId, args))\n}\n\nconst makeBinComment = (binId, comment) => (dispatch, getState) => {\n dispatch(updateBinReviewData(binId, {comment}))\n}\n\nconst makeQuestionComment = (binId, fieldName, comment) => (dispatch, getState) => {\n\n var args = {\n [fieldName]: {\n comment\n }\n }\n dispatch(updateBinReviewData(binId, args))\n\n}\n\n\nconst updateBinReviewData = (binId, args) => (dispatch, getState, { getFirebase, getFirestore}) => {\n const state = getState()\n const firestore = getFirestore()\n\n firestore.set(\n {\n collection: 'waste_audits',\n doc: state.app.wasteAuditDocumentId,\n subcollections: [{ collection: 'binReviews', doc: binId }],\n },\n args,\n { merge: true }\n ).then(() => {\n dispatch({ type: 'UPDATE SUCCESS' });\n }).catch(err => {\n dispatch({ type: 'UPDATE ERROR' }, err);\n });\n\n}\n\nexport {\n makeQuestionObservation,\n makeQuestionComment,\n makeBinComment\n}\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { RadioInput } from \"sharedComponents\";\nimport Comment from \"./Comment\";\nimport CompleteStatusIcon from \"./CompleteStatusIcon\";\nimport { Alert } from 'react-bootstrap'\nimport { faExclamationCircle } from \"@fortawesome/free-solid-svg-icons\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { scoreToClass, scoreToRiskLevel } from '../wasteAudit/selectors'\n\nvar NoScoreQuestionReview = ({\n fieldName,\n value,\n children,\n label,\n reviewData,\n decisionData,\n onDecision,\n onCommentChange,\n}) => {\n\n var {\n result,\n response,\n comment,\n } = reviewData[fieldName] || {}\n\n const decisionOptions = decisionData[fieldName]\n const radioOptions = _.map(decisionOptions, (decision) => ({ value: decision.response, label: decision.response, decision }) )\n\n var defaultValue = value || children || (\n \n {\" \"}\n Not Answered\n \n );\n\n var isComplete = _.isPresent(response) && !_.isNull(result)\n\n return(\n \n
\n
\n
\n
\n
\n
\n { onDecision(_.find(decisionOptions,{response}), fieldName, decisionOptions) }}\n />\n
\n
\n {\n onCommentChange(comment, fieldName)\n }}\n />\n
\n
\n
\n
\n
\n\n )\n}\n\n\nNoScoreQuestionReview.propTypes = {\n fieldName: PropTypes.string.isRequired,\n decisionData: PropTypes.object.isRequired,\n reviewData: PropTypes.object.isRequired,\n onDecision: PropTypes.func.isRequired,\n onCommentChange: PropTypes.func.isRequired,\n};\n\n\n//const mapStateToProps = (state, {}) => {\n //return {\n //}\n//}\n\n//const mapDispatchToProps = (dispatch, {}) => {\n //return {\n //}\n//}\n\n//QuestionReview = connect(\n //mapStateToProps,\n //mapDispatchToProps\n//)(QuestionReview)\n\n\nexport default NoScoreQuestionReview;\n\n\n\n\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { connect } from 'react-redux';\nimport NoScoreQuestionReview from \"./NoScoreQuestionReview\";\nimport ImageView from \"./ImageView\";\nimport { makeQuestionComment, makeQuestionObservation } from '../binReviews/operations'\nimport { useRouteMatch } from \"react-router-dom\";\nimport { hasNoScoreObservation } from '../app/selectors'\n\n//import classNames from \"classnames\";\n//import { DropdownSelect, DateSelect, ModelErrors, Link } from 'sharedComponents'\n//import actions from '../slice/actions'\n//var {\n//} = actions\n\nconst isComplete = (binData) => {\n return _.every(Object.keys(_.pickBy(getRequiredFields(binData))), (attr) => {\n return hasNoScoreObservation(binData, attr)\n })\n}\nconst getRequiredFields = ({storageType}) => {\n const { labelingRequired, packagingRequired, checkSecurity } = storageType;\n\n var requiredFields = {\n clearlyIdentified: true,\n contentsClearlyShown: true,\n contaminationFound: true,\n clearlyLabelled: !!labelingRequired,\n packagedCorrectly: !!packagingRequired,\n isBinLocked: !!checkSecurity,\n isAreaLocked: !!checkSecurity\n }\n\n return requiredFields\n}\n\nvar BinReview = ( {\n binId,\n decisionData,\n bins,\n onDecision,\n onCommentChange,\n binData\n} ) => {\n\n //let x = useRouteMatch();\n //\n if(binData) {\n\n const {\n name,\n title,\n containerType,\n isBinLocked,\n isAreaLocked,\n storageType,\n exteriorPhoto,\n interiorPhoto,\n contaminantNames,\n hasCorrectLabel,\n reviewData,\n } = binData\n\n const questionReviewProps = {\n onDecision,\n reviewData,\n decisionData,\n onCommentChange\n }\n\n const requiredFields = getRequiredFields(binData)\n\n return(\n \n
\n
\n \n \n { requiredFields['clearlyLabelled'] ?
\n \n : null }\n
\n \n \n { requiredFields['isBinLocked'] ?
: null }\n\n { requiredFields['isAreaLocked'] ?
: null }\n\n { requiredFields['packagedCorrectly'] ?
\n \n : null }\n\n
\n \n Contamination identified in Audit: \n \n {_.join(contaminantNames, ', ') }\n
\n \n \n
\n )\n\n } else {\n return null\n }\n}\n\n\nBinReview.propTypes = {\n binData: PropTypes.shape({\n id: PropTypes.string.isRequired,\n title: PropTypes.string.isRequired,\n name: PropTypes.string.isRequired,\n }).isRequired\n};\n\nconst mapStateToProps = (state, { binData }) => {\n return state\n};\n\nconst mapDispatchToProps = (dispatch, { binData }) => {\n return {\n onDecision: (decision, fieldName, decisionOptions) => {\n dispatch(makeQuestionObservation(binData.id, fieldName, decision, decisionOptions ));\n },\n onCommentChange: (comment, fieldName) => dispatch(makeQuestionComment(binData.id, fieldName, comment))\n };\n};\n\nBinReview = connect(\n mapStateToProps,\n mapDispatchToProps\n)(BinReview);\n\n\nexport default BinReview;\n\nexport {\n isComplete,\n getRequiredFields\n}\n\n\n\n\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { connect } from 'react-redux';\nimport ImageView from './ImageView'\nimport SummaryField from './SummaryField'\nimport Comment from \"./Comment\";\nimport CompleteStatusIcon from \"./CompleteStatusIcon\";\nimport { makeBinComment } from '../binReviews/operations'\nimport { getRequiredFields } from './BinReview'\n//import classNames from \"classnames\";\n//import { DropdownSelect, DateSelect, ModelErrors, Link } from 'sharedComponents'\n//import actions from '../slice/actions'\n//var {\n//} = actions\n\nvar BinSummary = ({\n onReview,\n onCommentChange,\n decisionData,\n binData\n}) => {\n\n const requiredReviewFields = getRequiredFields(binData)\n\n const {\n id,\n name,\n title,\n isComplete,\n isAreaLocked,\n isBinLocked,\n containerType,\n storageType,\n exteriorPhoto,\n interiorPhoto,\n storageAreaDescription,\n contaminantNames,\n hasCorrectLabel,\n reviewData,\n } = binData\n\n\n const { comment } = reviewData\n const { labelingRequired, checkSecurity } = storageType;\n\n return(\n \n
\n
\n
\n
\n
\n
Audit Answers
\n { storageAreaDescription ?
: null }\n { labelingRequired ?
: null }\n { checkSecurity ?
: null }\n { checkSecurity ?
: null }\n
\n
\n
\n
Review Response
\n { requiredReviewFields['clearlyIdentified'] ?
: null }\n { requiredReviewFields['contentsClearlyShown'] ?
: null }\n { requiredReviewFields['clearlyLabelled'] ?
: null }\n { requiredReviewFields['packagedCorrectly'] ?
: null }\n { requiredReviewFields['isBinLocked'] ?
: null }\n { requiredReviewFields['isAreaLocked'] ?
: null }\n { requiredReviewFields['contaminationFound'] ?
: null }\n
\n
\n
\n
\n
\n
\n
\n )\n}\n\n\n\nBinSummary.propTypes = {\n binData: PropTypes.shape({\n name: PropTypes.string.isRequired,\n id: PropTypes.string.isRequired,\n }).isRequired,\n};\n\n\nconst mapStateToProps = (state, props) => {\n return state\n}\n\nconst mapDispatchToProps = (dispatch, { binData }) => {\n return {\n onCommentChange: (comment) => dispatch(makeBinComment(binData.id, comment))\n };\n};\n\nBinSummary = connect(\n mapStateToProps,\n mapDispatchToProps\n)(BinSummary);\n\nexport default BinSummary;\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { Badge, Panel } from 'react-bootstrap';\nimport Comment from \"./Comment\";\nimport Action from \"./Action\";\nimport CompleteStatusIcon from \"./CompleteStatusIcon\";\nimport { Alert } from 'react-bootstrap'\nimport { faExclamationCircle } from \"@fortawesome/free-solid-svg-icons\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { scoreToClass, scoreToRiskLevel } from '../wasteAudit/selectors'\n\nvar AutoQuestionReview = ({\n fieldName,\n value,\n children,\n label,\n reviewData,\n decisionData,\n onCommentChange,\n}) => {\n\n var {\n score,\n response,\n comment,\n action,\n maxScore\n } = reviewData[fieldName] || {}\n\n const decisionOptions = decisionData[fieldName]\n const radioOptions = _.map(decisionOptions, (decision) => ({ value: decision.response, label: decision.response, decision }) )\n\n var defaultValue = value || children || (\n \n {\" \"}\n Not Answered\n \n );\n\n var isComplete = _.isPresent(response) && _.isPresent(score)\n\n return(\n \n
\n
\n
{label}
\n
\n { _.isPresent(score) ? `${score} / ${maxScore}` : null }\n
\n
\n
\n
\n
\n
\n
\n {response || 'complete above review'}\n
\n
\n
\n {\n onCommentChange(comment, fieldName)\n }}\n />\n
\n
\n
\n
\n
\n\n )\n}\n\n\nAutoQuestionReview.propTypes = {\n fieldName: PropTypes.string.isRequired,\n decisionData: PropTypes.object.isRequired,\n reviewData: PropTypes.object.isRequired,\n onCommentChange: PropTypes.func.isRequired,\n};\n\n\n//const mapStateToProps = (state, {}) => {\n //return {\n //}\n//}\n\n//const mapDispatchToProps = (dispatch, {}) => {\n //return {\n //}\n//}\n\n//QuestionReview = connect(\n //mapStateToProps,\n //mapDispatchToProps\n//)(QuestionReview)\n\n\nexport default AutoQuestionReview;\n\n\n\n\n\n\n","import { makeObservation } from '../app/selectors'\n\nconst makeQuestionObservation = (roomId, fieldName, decision, allOptions) => (dispatch, getState) => {\n\n var args = {\n [fieldName]: makeObservation(decision, allOptions, getState())\n }\n\n dispatch(updateRoomReviewData(roomId, args))\n\n}\n\nconst makeQuestionComment = (roomId, fieldName, comment) => (dispatch, getState) => {\n\n var args = {\n [fieldName]: {\n comment\n }\n }\n\n dispatch(updateRoomReviewData(roomId, args))\n\n}\n\nconst updateRoomReviewData = (roomId, args) => (dispatch, getState, { getFirebase, getFirestore}) => {\n const state = getState()\n const firestore = getFirestore()\n\n firestore.set(\n {\n collection: 'waste_audits',\n doc: state.app.wasteAuditDocumentId,\n subcollections: [{ collection: 'roomReviews', doc: roomId }],\n },\n args,\n { merge: true }\n ).then(() => {\n dispatch({ type: 'UPDATE SUCCESS' });\n }).catch(err => {\n dispatch({ type: 'UPDATE ERROR' }, err);\n });\n\n}\n\nexport {\n makeQuestionObservation,\n makeQuestionComment\n //makeRoomComment,\n}\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { connect } from 'react-redux';\nimport BinSummary from './BinSummary'\nimport BinReview from './BinReview'\nimport ImageView from './ImageView'\nimport AutoQuestionReview from './AutoQuestionReview'\nimport { makeQuestionComment, makeQuestionObservation } from '../roomReviews/operations'\nimport { hasNoScoreObservation, hasObservation, getObservationResult } from '../app/selectors'\nimport { ModalRoute } from \"react-router-modal\";\nimport { useHistory, useRouteMatch, Route, Switch, Redirect } from \"react-router-dom\";\nimport { mapReviewResult } from '../app/selectors'\nimport {\n getSectionTitle,\n getSectionNumber,\n} from '../components/sectionReviews'\n\nconst isComplete = (roomData) => {\n return _.every(Object.keys(_.pickBy(getRequiredFields(roomData))), (attr) => {\n return hasObservation(roomData, attr)\n })\n}\n\nconst getRequiredFields = () => {\n\n var requiredFields = {\n hasClinicalBins: true,\n hasNonClinicalBins: true,\n allRequiredContainersLabeled: true,\n contaminationFound: true\n }\n\n return requiredFields\n}\n\n\nconst getReviewResult = (roomData) => {\n const { reviewData, title, sectionId } = roomData\n return mapReviewResult(getRequiredFields(roomData), reviewData, `${getSectionNumber(sectionId)} - ${getSectionTitle(sectionId)} | ${title}`)\n}\n\nconst getCalculatedFields = (roomData, state) => {\n\n var x = {\n hasClinicalBins: ({bins}) => {\n const clinicalBins = _.filter(bins, (bin) => _.get(bin, 'containerType.wasteStreamId') == 'clinical')\n const allBinsWithResult = _.every(clinicalBins, (bin) => hasNoScoreObservation(bin, 'clearlyIdentified') )\n\n if(allBinsWithResult) {\n const clearlyIdentified = _.filter(clinicalBins, (bin) => getObservationResult(bin, 'clearlyIdentified') )\n return { clinicalBins, clearlyIdentified }\n }\n\n },\n hasNonClinicalBins: ({bins}) => {\n const nonClinicalBins = _.filter(bins, (bin) => _.get(bin, 'containerType.wasteStreamId') != 'clinical')\n const allBinsWithResult = _.every(nonClinicalBins, (bin) => hasNoScoreObservation(bin, 'clearlyIdentified') )\n\n if(allBinsWithResult) {\n const clearlyIdentified = _.filter(nonClinicalBins, (bin) => getObservationResult(bin, 'clearlyIdentified') )\n return { nonClinicalBins, clearlyIdentified }\n }\n },\n allRequiredContainersLabeled: ({bins}) => {\n const withLabelingRequired = _.filter(bins, (bin) => _.get(bin, 'storageType.labelingRequired'))\n const allBinsWithResult = _.every(withLabelingRequired, (bin) => hasNoScoreObservation(bin, 'clearlyLabelled') )\n if(allBinsWithResult) {\n const withClearLabels = _.filter(withLabelingRequired, (bin) => getObservationResult(bin, 'clearlyLabelled'))\n return { withLabelingRequired, withClearLabels }\n }\n },\n contaminationFound: ({bins}) => {\n const allBinsWithResult = _.every(bins, (bin) => hasNoScoreObservation(bin, 'contaminationFound') && hasNoScoreObservation(bin, 'contentsClearlyShown') )\n if(allBinsWithResult) {\n const withContamination = _.filter(bins, (bin) => _.isInteger(getObservationResult(bin, 'contaminationFound')) )\n const highestRiskLevel = _(withContamination).map((bin) => getObservationResult(bin, 'contaminationFound')).max()\n const cannotAssesContamination = _.filter(bins, (bin) => getObservationResult(bin, 'contaminationFound') === 'cannot_assess' )\n const contaminationAssessed = _.filter(bins, (bin) => getObservationResult(bin, 'contaminationFound') != 'cannot_assess' )\n const noContamination = _.filter(bins, (bin) => getObservationResult(bin, 'contaminationFound') === 'none' )\n return { withContamination, highestRiskLevel, noContamination, cannotAssesContamination, contaminationAssessed }\n }\n\n }\n }\n\n if(roomData.notAudited) {\n return _.mapValues(x, (f) => ({roomNotAudited: true}));\n } else {\n return _.mapValues(x, (f) => f(roomData, state) );\n }\n\n}\n\n\nvar RoomReview = ({\n roomData,\n decisionData,\n number,\n onDecision,\n onCommentChange\n}) => {\n\n const {\n name,\n notAudited,\n type,\n reviewData,\n bins,\n title,\n numberedTitle,\n hasClinicalBins,\n hasNonClinicalBins,\n contaminationFound,\n allRequiredContainersLabeled,\n } = roomData\n\n var history = useHistory()\n let { url } = useRouteMatch();\n\n\n const questionReviewProps = {\n onDecision,\n reviewData,\n decisionData: decisionData.rooms,\n onCommentChange\n }\n\n return (\n \n {\n const binData = _.find(bins, {id: match.params.binId})\n return(binData ?\n : )\n }}\n />\n \n \n
\n
\n {\n _.map(bins, (bin) => {\n return
history.push(`${url}/bins/${bin.id}`) }\n binData={bin}\n />\n })\n }\n\n \n {\n _.isPresent(_.get(hasClinicalBins, 'clearlyIdentified')) ?\n \n { _.map(_.get(hasClinicalBins, 'clearlyIdentified'), ({exteriorPhoto, id}) => ) }\n
: notAudited ? null : 'None'\n }\n \n \n {\n _.isPresent(_.get(hasNonClinicalBins, 'clearlyIdentified')) ?\n \n { _.map(_.get(hasNonClinicalBins, 'clearlyIdentified'), ({exteriorPhoto, id}) => ) }\n
: notAudited ? null : 'None'\n }\n \n \n { allRequiredContainersLabeled && !notAudited?\n (_.isPresent(allRequiredContainersLabeled.withLabelingRequired) ?\n \n {allRequiredContainersLabeled.withClearLabels.length} / {allRequiredContainersLabeled.withLabelingRequired.length} clearly labeled\n
\n : 'No containment with requirement to audit' ) : null\n }\n \n \n {\n contaminationFound && !notAudited ? : null\n }\n\n \n \n
\n \n \n );\n}\n\n\nvar ContaminationAnswer = ({contaminationFound}) => {\n if(contaminationFound) {\n const {\n withContamination,\n highestRiskLevel,\n noContamination,\n cannotAssesContamination,\n contaminationAssessed\n } = contaminationFound\n\n\n var assesedBins = _.isPresent(contaminationAssessed) ?\n \n {noContamination.length} / {contaminationAssessed.length} container{noContamination.length > 1 ? 's' : ''} without contamination\n
: null\n\n var notAssesedBins = _.isPresent(contaminationFound.cannotAssesContamination) ?\n \n {cannotAssesContamination.length} container{cannotAssesContamination.length > 1 ? 's' : ''} with insufficient information\n
: null\n\n var noBins = !(notAssesedBins || assesedBins) ?\n \n No containment was audited\n
: null\n\n return(\n \n {assesedBins}\n {notAssesedBins}\n {noBins}\n
\n )\n\n } else {\n return null\n }\n\n}\n\n\nconst mapStateToProps = (state, {}) => {\n return {\n }\n}\n\nconst mapDispatchToProps = (dispatch, {roomData}) => {\n return {\n onCommentChange: (comment, fieldName) => {\n dispatch(makeQuestionComment(roomData.id, fieldName, comment ));\n },\n onDecision: (decision, fieldName, decisionOptions) => {\n dispatch(makeQuestionObservation(roomData.id, fieldName, decision, decisionOptions ));\n },\n }\n}\n\nRoomReview = connect(\n mapStateToProps,\n mapDispatchToProps\n)(RoomReview)\n\nexport default RoomReview;\n\nexport {\n isComplete,\n getRequiredFields,\n getCalculatedFields,\n getReviewResult\n}\n\n\n\n\n\n","import React, { useReducer } from \"react\";\nimport PropTypes from \"prop-types\";\nimport { compose } from \"redux\";\nimport { connect } from \"react-redux\";\nimport _ from \"lodashExtended\";\nimport dotProp from \"dot-prop-immutable\";\nimport SectionReview from \"../SectionReview\";\nimport QuestionReview from \"../QuestionReview\";\nimport DocumentView from \"../DocumentView\";\nimport CompleteStatusIcon from \"../CompleteStatusIcon\";\nimport RoomReview, {\n isComplete as isRoomComplete,\n} from \"../RoomReview\";\nimport { ModalRoute } from \"react-router-modal\";\nimport { useRouteMatch, Redirect, Switch, Route, useHistory } from \"react-router-dom\";\nimport { sumReviewResults } from '../../app/selectors'\nimport {\n makeQuestionObservation,\n makeQuestionComment\n} from '../../sectionReviews/operations'\nimport Chip from '@material-ui/core/Chip';\n\nconst SECTION_ID = \"internal_waste_containment\";\nconst TITLE = \"Internal Waste Containment\";\n\nconst d = dotProp;\n\nconst isComplete = (sectionData) => {\n return _.every(sectionData.rooms, (roomData) => isRoomComplete(roomData) )\n}\n\nconst getReviewResult = ({rooms}) => {\n return sumReviewResults(_.map(rooms, 'reviewResult'))\n}\n\nconst getRequiredFields = () => {\n\n var requiredFields = {\n }\n\n return requiredFields\n}\n\n\nvar InternalWasteContainment = ({\n onDecision,\n onCommentChange,\n decisionData,\n sectionData,\n ...rest\n} ) => {\n\n let { url } = useRouteMatch();\n\n const {\n rooms,\n reviewData,\n } = sectionData;\n\n const questionReviewProps = {\n onDecision,\n reviewData,\n decisionData,\n onCommentChange\n }\n\n let roomRoutePath = `${url}/rooms/:roomId`\n\n let match = useRouteMatch(roomRoutePath)\n let selectedRoomId = _.get(match, 'params.roomId')\n let history = useHistory();\n\n let selectedRoom = _.find(rooms, {id: selectedRoomId})\n\n return (\n \n \n {\n _.map(rooms, (room, index) => {\n\n const roomSelected = selectedRoomId == room.id\n\n return(\n \n history.push(`${url}/rooms/${room.id}`) }\n icon={}\n color=\"primary\"\n />\n \n )\n })}\n \n\n \n
\n \n {\n selectedRoom ? \n \n : null\n }\n \n \n
\n
\n \n );\n};\n\nInternalWasteContainment.propTypes = {};\n\nconst mapStateToProps = (state, { }) => {\n return state\n};\n\nconst mapDispatchToProps = (dispatch, { }) => {\n return {\n onDecision: (decision, fieldName, decisionOptions) => {\n dispatch(makeQuestionObservation(SECTION_ID, fieldName, decision, decisionOptions ));\n },\n onCommentChange: (comment, fieldName) => {\n dispatch(makeQuestionComment(SECTION_ID, fieldName, comment ));\n },\n };\n};\n\nInternalWasteContainment = connect(\n mapStateToProps,\n mapDispatchToProps\n)(InternalWasteContainment);\n\n\nexport default {\n sectionId: SECTION_ID,\n title: TITLE,\n isComplete,\n getReviewResult,\n getRequiredFields,\n Component: InternalWasteContainment,\n}\n\n\n\n","import { makeNoScoreObservation } from '../app/selectors'\n\nconst makeQuestionObservation = (bulkContainmentId, fieldName, decision, allOptions) => (dispatch, getState) => {\n\n var args = {\n [fieldName]: makeNoScoreObservation(decision, allOptions, getState())\n }\n\n dispatch(updateBulkContainmentReviewData(bulkContainmentId, args))\n\n}\n\nconst makeQuestionComment = (bulkContainmentId, fieldName, comment) => (dispatch, getState) => {\n\n var args = {\n [fieldName]: {\n comment\n }\n }\n dispatch(updateBulkContainmentReviewData(bulkContainmentId, args))\n\n}\n\nconst makeBulkContainmentComment = (bulkContainmentId, comment) => (dispatch, getState) => {\n\n dispatch(updateBulkContainmentReviewData(bulkContainmentId, {comment}))\n\n}\n\n\nconst updateBulkContainmentReviewData = (bulkContainmentId, args) => (dispatch, getState, { getFirebase, getFirestore}) => {\n const state = getState()\n const firestore = getFirestore()\n\n firestore.set(\n {\n collection: 'waste_audits',\n doc: state.app.wasteAuditDocumentId,\n subcollections: [{ collection: 'bulkContainmentReviews', doc: bulkContainmentId }],\n },\n args,\n { merge: true }\n ).then((x) => {\n dispatch({ type: 'UPDATE SUCCESS' });\n }).catch(err => {\n dispatch({ type: 'UPDATE ERROR' }, err);\n });\n\n}\n\nexport {\n makeQuestionObservation,\n makeQuestionComment,\n makeBulkContainmentComment\n}\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { connect } from 'react-redux';\nimport NoScoreQuestionReview from \"./NoScoreQuestionReview\";\nimport ImageView from \"./ImageView\";\nimport { hasNoScoreObservation } from '../app/selectors'\nimport { makeQuestionComment, makeQuestionObservation } from '../bulkContainmentReviews/operations'\nimport { useRouteMatch } from \"react-router-dom\";\n\nconst isComplete = (bulkContainmentData) => {\n return _.every(Object.keys(_.pickBy(getRequiredFields(bulkContainmentData))), (attr) => {\n return hasNoScoreObservation(bulkContainmentData, attr)\n })\n}\n\nconst getRequiredFields = ({id, reviewData, storageType}) => {\n const { checkSecurity, packagingRequired } = storageType;\n\n var requiredFields = {\n clearlyIdentified: true,\n contaminationFound: true,\n isPubliclyAccessible: !!checkSecurity,\n isAreaLocked: !!checkSecurity,\n packagedCorrectly: !!packagingRequired\n }\n\n return requiredFields\n}\n\nvar BulkContainmentReview = ( {\n bulkContainmentId,\n decisionData,\n bulkContainments,\n onDecision,\n onCommentChange,\n bulkContainmentData\n} ) => {\n\n //let x = useRouteMatch();\n\n const {\n name,\n title,\n storageType,\n bulkStorageAreaPhoto,\n isPubliclyAccessible,\n isAreaLocked,\n contaminantNames,\n reviewData,\n } = bulkContainmentData\n\n const questionReviewProps = {\n onDecision,\n reviewData,\n decisionData,\n onCommentChange\n }\n\n const requiredFields = getRequiredFields(bulkContainmentData)\n\n return(\n \n
\n
\n \n \n\n { requiredFields['isPubliclyAccessible'] ?
: null }\n\n { requiredFields['isAreaLocked'] ?
: null }\n\n { requiredFields['packagedCorrectly'] ?
\n \n : null }\n\n
\n \n Contamination identified in Audit: \n \n {_.join(contaminantNames, ', ') }\n
\n \n \n
\n )\n}\n\n\nBulkContainmentReview.propTypes = {\n bulkContainmentData: PropTypes.shape({\n id: PropTypes.string.isRequired,\n title: PropTypes.string.isRequired,\n name: PropTypes.string.isRequired,\n }).isRequired\n};\n\nconst mapStateToProps = (state, { }) => {\n return state\n};\n\nconst mapDispatchToProps = (dispatch, { bulkContainmentData }) => {\n return {\n onDecision: (decision, fieldName, decisionOptions) => {\n dispatch(makeQuestionObservation(bulkContainmentData.id, fieldName, decision, decisionOptions ));\n },\n onCommentChange: (comment, fieldName) => dispatch(makeQuestionComment(bulkContainmentData.id, fieldName, comment))\n };\n};\n\nBulkContainmentReview = connect(\n mapStateToProps,\n mapDispatchToProps\n)(BulkContainmentReview);\n\n\nexport default BulkContainmentReview;\n\nexport {\n isComplete,\n getRequiredFields\n}\n\n\n\n\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { connect } from 'react-redux';\nimport ImageView from './ImageView'\nimport SummaryField from './SummaryField'\nimport Comment from \"./Comment\";\nimport CompleteStatusIcon from \"./CompleteStatusIcon\";\nimport { makeBulkContainmentComment } from '../bulkContainmentReviews/operations'\nimport { getRequiredFields } from './BulkContainmentReview'\n\n//import classNames from \"classnames\";\n//import { DropdownSelect, DateSelect, ModelErrors, Link } from 'sharedComponents'\n//import actions from '../slice/actions'\n//var {\n//} = actions\n\n\nvar BulkContainmentSummary = ({\n onReview,\n onCommentChange,\n decisionData,\n bulkContainmentData\n}) => {\n\n const requiredReviewFields = getRequiredFields(bulkContainmentData)\n\n const {\n name,\n title,\n isComplete,\n storageType,\n storageAreaDescription,\n isPubliclyAccessible,\n isAreaLocked,\n bulkStorageAreaPhoto,\n contaminantNames,\n reviewData,\n } = bulkContainmentData\n\n const { checkSecurity } = storageType;\n\n\n const { comment } = reviewData\n\n return(\n \n
\n Review \n \n {title} \n
\n
\n
\n
\n
\n
Audit Answers
\n
\n { checkSecurity ?
: null }\n { checkSecurity ?
: null }\n
\n
\n
Review Response
\n { requiredReviewFields['clearlyIdentified'] ?
: null }\n { requiredReviewFields['packagedCorrectly'] ?
: null }\n { requiredReviewFields['isPubliclyAccessible'] ?
: null }\n { requiredReviewFields['isAreaLocked'] ?
: null }\n { requiredReviewFields['contaminationFound'] ?
: null }\n
\n
\n
\n
\n
\n
\n
\n )\n}\n\n\n\nBulkContainmentSummary.propTypes = {\n bulkContainmentData: PropTypes.shape({\n name: PropTypes.string.isRequired,\n id: PropTypes.string.isRequired,\n }).isRequired,\n};\n\n\nconst mapStateToProps = (state, props) => {\n return state\n}\n\nconst mapDispatchToProps = (dispatch, { bulkContainmentData }) => {\n return {\n onCommentChange: (comment) => dispatch(makeBulkContainmentComment(bulkContainmentData.id, comment))\n };\n};\n\nBulkContainmentSummary = connect(\n mapStateToProps,\n mapDispatchToProps\n)(BulkContainmentSummary);\n\nexport default BulkContainmentSummary;\n\n","import { makeObservation } from '../app/selectors'\n\nconst makeQuestionObservation = (wasteStreamId, fieldName, decision, allOptions) => (dispatch, getState) => {\n\n var args = {\n [fieldName]: makeObservation(decision, allOptions, getState())\n }\n\n dispatch(updateWasteStreamReviewData(wasteStreamId, args))\n\n}\n\nconst makeQuestionComment = (wasteStreamId, fieldName, comment) => (dispatch, getState) => {\n\n var args = {\n [fieldName]: {\n comment\n }\n }\n\n dispatch(updateWasteStreamReviewData(wasteStreamId, args))\n\n}\n\nconst updateWasteStreamReviewData = (wasteStreamId, args) => (dispatch, getState, { getFirebase, getFirestore}) => {\n const state = getState()\n const firestore = getFirestore()\n\n firestore.set(\n {\n collection: 'waste_audits',\n doc: state.app.wasteAuditDocumentId,\n subcollections: [{ collection: 'wasteStreamReviews', doc: wasteStreamId }],\n },\n args,\n { merge: true }\n ).then(() => {\n dispatch({ type: 'UPDATE SUCCESS' });\n }).catch(err => {\n dispatch({ type: 'UPDATE ERROR' }, err);\n });\n\n}\n\nexport {\n makeQuestionObservation,\n makeQuestionComment\n //makeWasteStreamComment,\n}\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { connect } from 'react-redux';\nimport BinReview from './BinReview'\nimport BulkContainmentReview from './BulkContainmentReview'\nimport BinSummary from './BinSummary'\nimport ImageView from './ImageView'\nimport BulkContainmentSummary from './BulkContainmentSummary'\nimport AutoQuestionReview from './AutoQuestionReview'\nimport { makeQuestionComment } from '../wasteStreamReviews/operations'\nimport { ModalRoute } from \"react-router-modal\";\nimport { useHistory, useRouteMatch, Switch, Route, Redirect } from \"react-router-dom\";\nimport { hasNoScoreObservation, hasObservation, getObservationResult } from '../app/selectors'\nimport { mapReviewResult } from '../app/selectors'\nimport {\n getSectionTitle,\n getSectionNumber,\n} from '../components/sectionReviews'\n\nconst isComplete = (wasteStreamData) => {\n return _.every(Object.keys(_.pickBy(getRequiredFields(wasteStreamData))), (attr) => {\n return hasObservation(wasteStreamData, attr)\n })\n}\n\nconst getRequiredFields = ({storageType}) => {\n const { checkSecurity, packagingRequired } = storageType;\n\n var requiredFields = {\n hasStorage: true,\n contaminationFound: true,\n storedSecurely: !!checkSecurity,\n packagedCorrectly: !!packagingRequired\n }\n\n return requiredFields\n}\n\nconst getReviewResult = (wasteStreamData) => {\n const { reviewData, title, sectionId } = wasteStreamData\n return mapReviewResult(getRequiredFields(wasteStreamData), reviewData, `${getSectionNumber(sectionId)} - ${getSectionTitle(sectionId)} | ${title}`)\n}\n\nconst combineContainment = (bins,bulkContainments ) => _([bins,bulkContainments]).flatten().value()\n\nconst getCalculatedFields = (wasteStreamData, state) => {\n\n var x = {\n hasStorage: ({bins, bulkContainments}) => {\n var allContainments = combineContainment(bins, bulkContainments)\n const allWithResult = _.every(allContainments, (containment) => hasNoScoreObservation(containment, 'clearlyIdentified') )\n\n if(allWithResult) {\n const clearlyIdentified = _.filter(allContainments, (containment) => getObservationResult(containment, 'clearlyIdentified') )\n return { allContainments, clearlyIdentified }\n }\n\n },\n storedSecurely: ({bins, bulkContainments}) => {\n const binsWithSecurityRequired = _.filter(bins, (bin) => _.get(bin, 'storageType.checkSecurity'))\n const bulkContainmentsWithSecurityRequired = _.filter(bulkContainments, (bulkContainment) => _.get(bulkContainment, 'storageType.checkSecurity'))\n\n const allBinsWithResult = _.every(binsWithSecurityRequired, (bin) => hasNoScoreObservation(bin, 'isBinLocked') && hasNoScoreObservation(bin, 'isAreaLocked') )\n const allBulkContainmentsWithResult = _.every(bulkContainmentsWithSecurityRequired, (bin) => hasNoScoreObservation(bin, 'isPubliclyAccessible') && hasNoScoreObservation(bin, 'isAreaLocked') )\n\n if(allBinsWithResult && allBulkContainmentsWithResult) {\n const secureBins = _.filter(binsWithSecurityRequired, (bin) => getObservationResult(bin, 'isBinLocked') && getObservationResult(bin, 'isAreaLocked') )\n const notSecureBins = _.reject(binsWithSecurityRequired, (bin) => getObservationResult(bin, 'isBinLocked') && getObservationResult(bin, 'isAreaLocked') )\n\n const secureBulkContainments = _.filter(bulkContainmentsWithSecurityRequired, (bulkContainment) => getObservationResult(bulkContainment, 'isPubliclyAccessible') && getObservationResult(bulkContainment, 'isAreaLocked') )\n const notSecureBulkContainments = _.reject(bulkContainmentsWithSecurityRequired, (bulkContainment) => getObservationResult(bulkContainment, 'isPubliclyAccessible') && getObservationResult(bulkContainment, 'isAreaLocked') )\n\n return {\n secureContainment: [...secureBins, ...secureBulkContainments],\n notSecureContainment: [...notSecureBins, ...notSecureBulkContainments],\n containmentWithSecurityRequired: [...binsWithSecurityRequired, ...bulkContainmentsWithSecurityRequired]\n }\n }\n },\n packagedCorrectly: ({bins, bulkContainments}) => {\n var allContainments = combineContainment(bins, bulkContainments)\n const withPackagingRequired = _.filter(allContainments, (containment) => _.get(containment, 'storageType.packagingRequired'))\n const allWithResult = _.every(withPackagingRequired, (containment) => hasNoScoreObservation(containment, 'packagedCorrectly') )\n if(allWithResult) {\n const withCorrectPackaging = _.filter(withPackagingRequired, (containment) => getObservationResult(containment, 'packagedCorrectly'))\n const withoutCorrectPackaging = _.reject(withPackagingRequired, (containment) => getObservationResult(containment, 'packagedCorrectly'))\n return { withPackagingRequired, withCorrectPackaging, withoutCorrectPackaging }\n }\n },\n contaminationFound: ({bins, bulkContainments}) => {\n var allContainments = combineContainment(bins, bulkContainments)\n\n const allContainmentWithResult = _.every(allContainments, (containment) => hasNoScoreObservation(containment, 'contaminationFound') )\n if(allContainmentWithResult) {\n const withContamination = _.filter(allContainments, (containment) => _.isInteger(getObservationResult(containment, 'contaminationFound')) )\n const highestRiskLevel = _(withContamination).map((containment) => getObservationResult(containment, 'contaminationFound')).max()\n const cannotAssesContamination = _.filter(allContainments, (containment) => getObservationResult(containment, 'contaminationFound') === 'cannot_assess' )\n const contaminationAssessed = _.filter(allContainments, (containment) => getObservationResult(containment, 'contaminationFound') != 'cannot_assess' )\n const noContamination = _.filter(allContainments, (containment) => getObservationResult(containment, 'contaminationFound') === 'none' )\n return { withContamination, highestRiskLevel, noContamination, cannotAssesContamination, contaminationAssessed }\n }\n }\n }\n\n return _.mapValues(x, (f) => f(wasteStreamData, state) );\n}\n\n\n\nvar WasteStreamReview = ({\n wasteStreamData,\n decisionData,\n onBinCommentChange,\n onDecision,\n onCommentChange\n}) => {\n\n const {\n name,\n title,\n type,\n reviewData,\n bins,\n hasStorage,\n storedSecurely,\n packagedCorrectly,\n contaminationFound,\n bulkContainments,\n } = wasteStreamData\n\n var history = useHistory()\n let { url } = useRouteMatch();\n\n const questionReviewProps = {\n onDecision,\n reviewData,\n decisionData: decisionData.wasteStreams,\n onCommentChange\n }\n\n const requiredFields = getRequiredFields(wasteStreamData)\n\n return (\n \n {\n const binData = _.find(bins, {id: match.params.binId})\n return(binData ?\n : )\n }}\n />\n {\n const bulkContainmentData = _.find(bulkContainments, {id: match.params.bulkContainmentId})\n return(bulkContainmentData ?\n : )\n }}\n />\n \n \n
\n
\n {\n _.map(bins, (bin) => {\n return
history.push(`${url}/bins/${bin.id}/review`) }\n binData={bin}\n />\n })\n }\n {\n _.map(bulkContainments, (bulkContainment) => {\n return history.push(`${url}/bulkContainments/${bulkContainment.id}/review`) }\n bulkContainmentData={bulkContainment}\n />\n })\n }\n \n {\n requiredFields['hasStorage'] ?\n \n {\n _.isPresent(_.get(hasStorage, 'clearlyIdentified')) ?\n \n { _.map(_.get(hasStorage, 'clearlyIdentified'), ({exteriorPhoto, bulkStorageAreaPhoto, id}) =>\n ) }\n
: 'None Reported'\n }\n : null\n }\n {\n requiredFields['storedSecurely'] ?\n \n { storedSecurely ? : null }\n : null\n }\n {\n requiredFields['packagedCorrectly'] ?\n \n { packagedCorrectly ? : null }\n : null\n }\n {\n requiredFields['contaminationFound'] ?\n \n { contaminationFound ? : null }\n : null\n }\n\n \n
\n \n \n\n );\n}\n\nconst PackagedCorrectly = ({withoutCorrectPackaging, withPackagingRequired}) => {\n\n if(withPackagingRequired.length == 0) {\n return No containment audited
\n } else {\n return \n { _.map(withoutCorrectPackaging, ({exteriorPhoto, bulkStorageAreaPhoto, id}) =>\n ) }\n
\n }\n}\n\nconst StoredSecurely = ({\n secureContainment,\n notSecureContainment,\n containmentWithSecurityRequired\n}) => {\n\n if(containmentWithSecurityRequired.length == 0) {\n return No containment audited
\n } else {\n return \n\n
\n { secureContainment.length } / {containmentWithSecurityRequired.length} stored securely\n
\n { _.map(notSecureContainment, ({exteriorPhoto, bulkStorageAreaPhoto, id}) =>\n
) }\n
\n }\n}\n\nconst ContaminationFound = ({\n withContamination,\n highestRiskLevel,\n noContamination,\n cannotAssesContamination,\n contaminationAssessed\n\n}) => {\n\n var assesedBins = _.isPresent(contaminationAssessed) ?\n \n {noContamination.length} / {contaminationAssessed.length} bulk containment without contamination\n
: null\n\n var notAssesedBins = _.isPresent(cannotAssesContamination) ?\n \n {cannotAssesContamination.length} bulk containment with insufficient information\n
: null\n\n var noBins = !(notAssesedBins || assesedBins) ?\n \n No bulk containment was audited\n
: null\n\n return(\n \n {assesedBins}\n {notAssesedBins}\n {noBins}\n
\n )\n}\n\n\n\nconst mapStateToProps = (state, {}) => {\n return {\n }\n}\n\nWasteStreamReview.propTypes = {\n}\n\nconst mapDispatchToProps = (dispatch, {wasteStreamData}) => {\n return {\n onCommentChange: (comment, fieldName) => {\n dispatch(makeQuestionComment(wasteStreamData.id, fieldName, comment ));\n }\n }\n}\n\nWasteStreamReview = connect(\n mapStateToProps,\n mapDispatchToProps\n)(WasteStreamReview)\n\nexport default WasteStreamReview;\n\nexport {\n isComplete,\n getRequiredFields,\n getCalculatedFields,\n getReviewResult\n}\n\n\n\n\n\n","import React, { useReducer } from \"react\";\nimport PropTypes from \"prop-types\";\nimport { compose } from \"redux\";\nimport { connect } from \"react-redux\";\nimport _ from \"lodashExtended\";\nimport dotProp from \"dot-prop-immutable\";\nimport SectionReview from \"../SectionReview\";\nimport QuestionReview from \"../QuestionReview\";\nimport CompleteStatusIcon from \"../CompleteStatusIcon\";\nimport WasteStreamReview, { isComplete as isWasteStreamComplete } from \"../WasteStreamReview\";\nimport { useRouteMatch, Switch, Redirect, Route, useHistory } from \"react-router-dom\";\nimport { sumReviewResults } from '../../app/selectors'\nimport {\n makeQuestionObservation,\n makeQuestionComment\n} from '../../sectionReviews/operations'\nimport Chip from '@material-ui/core/Chip';\n\nconst SECTION_ID = \"bulk_waste_storage_containment\";\nconst TITLE = \"Bulk Waste Storage Containment\";\n\nconst d = dotProp;\n\nconst isComplete = (sectionData) => {\n return( _.every(sectionData.wasteStreams, (wasteStreamData) => isWasteStreamComplete(wasteStreamData) ) )\n}\n\nconst getReviewResult = ({wasteStreams}) => { \n return sumReviewResults(_.map(wasteStreams, 'reviewResult'))\n}\n\nconst getRequiredFields = () => {\n\n var requiredFields = {\n }\n\n return requiredFields\n}\n\nvar BulkWasteStorageContainment = ({\n onDecision,\n onCommentChange,\n decisionData,\n sectionData,\n ...rest\n} ) => {\n\n const {\n wasteStreams,\n reviewData,\n } = sectionData;\n\n\n const questionReviewProps = {\n onDecision,\n reviewData,\n decisionData,\n onCommentChange\n }\n\n\n let { url } = useRouteMatch();\n let wasteStreamRoutePath = `${url}/wasteStreams/:wasteStreamId`\n let match = useRouteMatch(wasteStreamRoutePath)\n let selectedWasteStreamId = _.get(match, 'params.wasteStreamId')\n let history = useHistory();\n\n let selectedWasteStream = _.find(wasteStreams, {id: selectedWasteStreamId})\n\n return (\n \n \n {\n _.map(wasteStreams, (wasteStream, index) => {\n\n const wasteStreamSelected = selectedWasteStreamId == wasteStream.id\n\n return(\n \n history.push(`${url}/wasteStreams/${wasteStream.id}`) : null }\n icon={}\n color=\"primary\"\n />\n \n )\n })}\n \n\n \n
\n \n {\n selectedWasteStream ? \n \n : null\n }\n \n \n
\n
\n \n );\n};\n\nBulkWasteStorageContainment.propTypes = {};\n\nconst mapStateToProps = (state, { wasteAudit }) => {\n return state\n};\n\nconst mapDispatchToProps = (dispatch, { }) => {\n return {\n onDecision: (decision, fieldName, decisionOptions) => {\n dispatch(makeQuestionObservation(SECTION_ID, fieldName, decision, decisionOptions ));\n },\n onCommentChange: (comment, fieldName) => {\n dispatch(makeQuestionComment(SECTION_ID, fieldName, comment ));\n },\n };\n};\n\nBulkWasteStorageContainment = connect(\n mapStateToProps,\n mapDispatchToProps\n)(BulkWasteStorageContainment);\n\n\nexport default {\n sectionId: SECTION_ID,\n title: TITLE,\n isComplete,\n getReviewResult,\n getRequiredFields,\n Component: BulkWasteStorageContainment,\n}\n\n\n\n","import generalInformationSection from './GeneralInformation'\nimport wasteManagementPolicySection from './WasteManagementPolicy'\nimport wasteManagementTrainingSection from './WasteManagementTraining'\nimport hazardousWasteConsignmentNotesSection from './HazardousWasteConsignmentNotes'\nimport internalWasteContainmentSection from './InternalWasteContainment'\nimport bulkWasteStorageContainmentSection from './BulkWasteStorageContainment'\nimport _ from 'lodashExtended'\nimport { hasObservation } from '../../app/selectors'\n\n\nconst orderedSections = [\n generalInformationSection,\n wasteManagementPolicySection,\n wasteManagementTrainingSection,\n hazardousWasteConsignmentNotesSection,\n internalWasteContainmentSection,\n bulkWasteStorageContainmentSection,\n]\n\n\nconst sectionWeights = {\n [generalInformationSection.sectionId]: 0.08,\n [wasteManagementPolicySection.sectionId]: 0.16,\n [wasteManagementTrainingSection.sectionId]: 0.20,\n [hazardousWasteConsignmentNotesSection.sectionId]: 0.16,\n [bulkWasteStorageContainmentSection.sectionId]: 0.2,\n [internalWasteContainmentSection.sectionId]: 0.2\n}\n\n\nconst orderedSectionReviewComponents = _.map(orderedSections, 'Component')\n//const orderedSectionSummaryViews = _.map(orderedSections, 'SummaryView')\n\n\nvar titleBySectionId = {}\n_.each(orderedSections, ({sectionId, title}) => titleBySectionId[sectionId] = title )\nconst getSectionTitle = (sectionId) => titleBySectionId[sectionId]\n\nvar requiredFieldsBySectionId = {}\n_.each(orderedSections, ({sectionId, getRequiredFields}) => requiredFieldsBySectionId[sectionId] = getRequiredFields )\nconst getSectionRequiredFields = (sectionData) => requiredFieldsBySectionId[sectionData.id](sectionData)\n\n\n\n\n\nconst defaultIsComplete = (sectionData) => {\n return _.every(Object.keys(_.pickBy(getSectionRequiredFields(sectionData))), (attr) => {\n return hasObservation(sectionData, attr)\n })\n}\nconst isCompleteBySectionId = {}\n_.each(orderedSections, ({sectionId, isComplete}) => isCompleteBySectionId[sectionId] = isComplete || defaultIsComplete )\nconst isSectionReviewComplete = (sectionData) => {\n return isCompleteBySectionId[sectionData.id](sectionData)\n}\n\n\n\nvar getReviewResultBySectionId = {}\n_.each(orderedSections, ({sectionId, getReviewResult}) => getReviewResultBySectionId[sectionId] = getReviewResult )\nconst getSectionReviewResult = (sectionData) => { \n\n const sectionWeight = sectionWeights[sectionData.id]\n var reviewResult = getReviewResultBySectionId[sectionData.id](sectionData)\n\n const percentScore = (reviewResult.score / reviewResult.maxScore) * 100.0\n const weightedPercentScore = percentScore * sectionWeight\n const weightedPercent = sectionWeight * 100.0\n\n return {\n percentScore,\n weightedPercentScore,\n weightedPercent,\n ...reviewResult\n }\n\n}\n\nconst orderedSectionIds = _.map(orderedSections, 'sectionId')\n\nconst getSectionNumber = (sectionId) => _.indexOf(orderedSectionIds, sectionId) + 1\n\nvar reviewComponentsById = {}\n_.each(orderedSections, ({sectionId, Component}) => reviewComponentsById[sectionId] = Component )\n\nexport default orderedSectionReviewComponents\n\nexport {\n orderedSectionReviewComponents,\n reviewComponentsById,\n getSectionTitle,\n orderedSectionIds,\n isSectionReviewComplete,\n getSectionReviewResult,\n getSectionNumber,\n sectionWeights,\n getSectionRequiredFields\n //sectionIncompleteMessage,\n //isSectionComplete,\n //orderedSections,\n //orderedSectionSummaryViews\n}\n\n\n\n\n\n\n\n\n","import _ from \"lodashExtended\";\nimport dotProp from \"dot-prop-immutable\";\nimport {\n getDecisionData,\n makeObservation,\n autoReviewData,\n getRequiredRoomCount\n} from \"../app/selectors\";\nimport {\n getRoomData as getAuditRoomData,\n getRoomsForSection as getAuditRoomsForSection\n} from \"../../auditor/rooms/selectors\";\nimport { getBinDataForRoom } from \"../binReviews/selectors\";\nimport {\n isComplete,\n getCalculatedFields,\n getReviewResult,\n getRequiredFields\n} from \"../components/RoomReview\";\nimport internalWasteContainment from \"../components/sectionReviews/InternalWasteContainment\";\n\nconst getRoomsWithReview = state => {\n const auditedRooms = getRoomsForSection(\n internalWasteContainment.sectionId,\n state\n );\n var requiredRoomCount = getRequiredRoomCount(state);\n\n const auditedCount = auditedRooms.length;\n\n const missingRooms =\n auditedCount < requiredRoomCount\n ? _(_.range(auditedCount + 1, requiredRoomCount + 1))\n .map(number => {\n return {\n id: `missing_room_${number}`,\n title: `Not Audited`,\n notAudited: true,\n sectionId: internalWasteContainment.sectionId\n };\n })\n .value()\n : [];\n\n const roomsToReview = auditedRooms.concat(missingRooms);\n\n return _(roomsToReview)\n .map((room, index) => {\n let roomData = getRoomWithReview(room, state);\n\n let number = index + 1;\n let numberedTitle = `Room ${number}: ${roomData.title}`;\n\n return {\n number,\n numberedTitle,\n ...roomData\n };\n })\n .value();\n};\n\nconst getRoomsForSection = (sectionId, state) => {\n return _(getAuditRoomsForSection(sectionId, state))\n .filter(({ type }) => _.isPresent(type))\n .value();\n};\n\nconst getRoomWithReview = (room, state) => {\n //const room = getAuditRoomData(roomId, state)\n\n var bins = getBinDataForRoom(room.id, state);\n\n var roomWithoutCalculatedFields = {\n ...room,\n bins\n };\n\n const roomWithoutReview = {\n ...roomWithoutCalculatedFields,\n ...getCalculatedFields(roomWithoutCalculatedFields, state)\n };\n\n const roomWithoutComplete = {\n ...roomWithoutReview,\n reviewData: getRoomReviewData(roomWithoutReview, state)\n };\n\n const roomWithoutResult = {\n ...roomWithoutComplete,\n isComplete: isComplete(roomWithoutComplete, state)\n };\n\n return {\n ...roomWithoutResult,\n reviewResult: getReviewResult(roomWithoutResult)\n };\n};\n\nconst getRoomReviewData = (room, state) => {\n var savedReviewData = dotProp.get(\n state.firestore,\n `data.roomReviews.${room.id}`,\n {}\n );\n\n const decisionData = getDecisionData(state).sections[room.sectionId].rooms;\n const requiredFields = getRequiredFields(room);\n\n return autoReviewData(\n room,\n requiredFields,\n savedReviewData,\n decisionData,\n makeObservation,\n state\n );\n};\n\nexport { getRoomsWithReview, getRoomsForSection };\n","import _ from 'lodashExtended'\nimport {\n getSectionTitle,\n getSectionNumber,\n getSectionRequiredFields\n} from '../components/sectionReviews'\nimport dotProp from 'dot-prop-immutable'\nimport { getDecisionData, makeObservation, autoReviewData } from '../app/selectors'\nimport {\n getSectionData as getAuditSectionData,\n} from '../../auditor/sections/selectors'\n\n//const autoReviewData = (inputData, requiredFields, savedReviewData, decisionData, getObservation, state) => {\n\nconst getSectionData = (sectionId, state) => {\n\n const sectionData = getAuditSectionData(sectionId, state)\n\n return {\n id: sectionId,\n title: getSectionTitle(sectionId),\n number: getSectionNumber(sectionId),\n ...sectionData\n }\n\n}\n\nconst getSectionReviewData = (sectionData, state) => {\n const { id: sectionId } = sectionData\n var savedReviewData = _.omit(dotProp.get(state.firestore, `data.sectionReviews.${sectionId}`) || {}, 'state')\n\n const decisionData = getDecisionData(state).sections[sectionId]\n const requiredFields = getSectionRequiredFields(sectionData)\n\n return autoReviewData(sectionData, requiredFields, savedReviewData, decisionData, makeObservation, state)\n}\n\n\nconst getSectionDataWithReview = (sectionId, state) => {\n var sectionData = getSectionData(sectionId, state)\n\n return {\n ...sectionData,\n reviewData: getSectionReviewData(sectionData, state)\n }\n\n}\n\n\nexport {\n getSectionReviewData,\n getSectionDataWithReview\n}\n\n","import _ from 'lodashExtended'\nimport dotProp from \"dot-prop-immutable\";\nimport { getDecisionData, makeNoScoreObservation, autoReviewData } from '../app/selectors'\nimport {\n getBinData as getAuditBinData,\n getBinsForRoom as getAuditBinsForRoom,\n getBinsForSection as getAuditBinsForSection\n} from '../../auditor/bins/selectors'\n\nimport { getContaminantNames } from '../../auditor/wasteAudit/selectors'\nimport { getRequiredFields } from '../components/BinReview'\nimport { isComplete } from '../components/BinReview'\nimport {\n getStorageType,\n getInternalContainerType,\n} from '../../auditor/app/selectors'\nimport { getAllContaminants } from '../../auditor/app/selectors'\nimport internalWasteContainment from '../components/sectionReviews/InternalWasteContainment'\nimport bulkWasteStorageContainment from '../components/sectionReviews/BulkWasteStorageContainment'\nimport { getRoomsForSection } from '../roomReviews/selectors'\nimport { getSectionDataWithReview } from '../sectionReviews/selectors';\n\nconst getStorageTypeData = (storageTypeId, state) => _.omit(getStorageType(storageTypeId, state), ['exampleInteriorPhotoUrl', 'exampleExteriorPhotoUrl', 'exampleBulkInternalPhotoUrl'])\nconst getContainerTypeData = (containerTypeId, state) => _.omit(getInternalContainerType(containerTypeId, state), ['exampleInteriorPhotoUrl', 'exampleExteriorPhotoUrl'])\n\n\nconst getBinData = (binId, state) => {\n\n const bin = getAuditBinData(binId, state)\n const name = _.get(bin, 'containerType.name') || _.get(bin, 'storageType.name')\n\n return {\n ...bin,\n id: binId,\n name,\n contaminantNames: getContaminantNames(bin.contaminants, getAllContaminants(state)),\n containerType: getContainerTypeData(bin.containerTypeId, state),\n storageType: getStorageTypeData(bin.storageTypeId, state)\n }\n}\n\n\nconst getBinReviewData = (binId, state) => {\n const binData = getBinData(binId, state)\n\n var reviewData = {}\n\n var savedReviewData = dotProp.get(state.firestore, `data.binReviews.${binId}`, {})\n const decisionData = getDecisionData(state).sections[binData.sectionId].bins\n const requiredFields = getRequiredFields(binData)\n\n return autoReviewData(binData, requiredFields, savedReviewData, decisionData, makeNoScoreObservation, state)\n}\n\nconst getBinsForRoom = (roomId, state) => {\n return _(getAuditBinsForRoom(roomId, state)).\n filter(({storageType, containerType, exteriorPhoto, interiorPhoto}) => {\n return(\n _.isPresent(containerType) &&\n _.isPresent(storageType) && (\n _.isPresent(exteriorPhoto) || _.isPresent(interiorPhoto)\n )\n )\n }).map(({id}) => getBinData(id, state)).value()\n}\n\nconst getBinsForWasteStream = (wasteStreamId, state) => {\n return _.filter(getBinsForSection(bulkWasteStorageContainment.sectionId, state), ({id}) => getWasteStreamIdForBin(id, state) == wasteStreamId)\n}\n\nconst getBinsForSection = (sectionId, state) => {\n\n var sectionBins\n if(sectionId == internalWasteContainment.sectionId) {\n sectionBins = _(getRoomsForSection(internalWasteContainment.sectionId, state)).map(({id}) => getBinsForRoom(id, state) ).flatten()\n } else if(sectionId == bulkWasteStorageContainment.sectionId) {\n var sectionData = getSectionDataWithReview(sectionId,state)\n sectionBins = sectionData['hasExternalContainment'] === 'yes' ?\n getAuditBinsForSection(sectionId, state) : []\n } else {\n sectionBins = []\n }\n\n return _(sectionBins).filter(({storageType, containerType, exteriorPhoto, interiorPhoto}) => {\n return(\n _.isPresent(storageType) && (\n _.isPresent(exteriorPhoto) || _.isPresent(interiorPhoto)\n )\n )\n }).map(({id}) => getBinData(id, state)).value()\n}\n\nconst getWasteStreamIdForBin = (binId, state) => {\n var bin = getBinData(binId, state)\n return _([getInternalContainerType(bin.containerTypeId, state), getStorageType(bin.storageTypeId, state)]).map('wasteStreamId').find(_.isPresent)\n}\n\nconst getBinDataForRoom = (roomId, state) => {\n\n return _.map(getBinsForRoom(roomId, state), (bin)=> {\n const binWithoutComplete = {\n ...bin,\n title: bin.name,\n reviewData: getBinReviewData(bin.id, state)\n }\n\n return {\n ...binWithoutComplete,\n isComplete: isComplete(binWithoutComplete, state)\n }\n\n })\n\n}\n\nconst getBinDataForWasteStream = (wasteStreamId, state) => {\n\n return _.map(getBinsForWasteStream(wasteStreamId, state), (bin)=> {\n\n const title = `${bin.name} - External Container`\n\n const binWithoutComplete = {\n ...bin,\n title,\n reviewData: getBinReviewData(bin.id, state)\n }\n\n return {\n ...binWithoutComplete,\n isComplete: isComplete(binWithoutComplete, state)\n }\n\n })\n\n}\n\nexport {\n getBinReviewData,\n getBinDataForRoom,\n getBinDataForWasteStream,\n getBinsForSection,\n getWasteStreamIdForBin,\n getBinData,\n}\n","import _ from 'lodashExtended'\nimport dotProp from \"dot-prop-immutable\";\nimport {\n getStorageType,\n} from '../../auditor/app/selectors'\nimport { getDecisionData, makeNoScoreObservation, autoReviewData } from '../app/selectors'\nimport {\n getBulkContainmentData as getAuditBulkContainmentData,\n getBulkContainmentsForRoom as getAuditBulkContainmentsForRoom,\n getBulkContainmentsForSection as getAuditBulkContainmentsForSection\n} from '../../auditor/bulkContainments/selectors'\nimport { getContaminantNames } from '../../auditor/wasteAudit/selectors'\nimport { getRequiredFields } from '../components/BulkContainmentReview'\nimport { isComplete } from '../components/BulkContainmentReview'\nimport bulkWasteStorageContainment from '../components/sectionReviews/BulkWasteStorageContainment'\nimport { getAllExternalContainerContaminants } from '../../auditor/app/selectors'\nimport { getSectionDataWithReview } from '../sectionReviews/selectors';\n\n\nconst getStorageTypeData = (storageTypeId, state) => _.omit(getStorageType(storageTypeId, state), ['exampleInteriorPhotoUrl', 'exampleExteriorPhotoUrl', 'exampleBulkInternalPhotoUrl'])\n\nconst getBulkContainmentData = (bulkContainmentId, state) => {\n\n const bulkContainment = getAuditBulkContainmentData(bulkContainmentId, state)\n const name = _.get(bulkContainment, 'storageType.name')\n\n return {\n id: bulkContainmentId,\n ...bulkContainment,\n name,\n contaminantNames: getContaminantNames(bulkContainment.contaminants, getAllExternalContainerContaminants(state)),\n storageType: getStorageTypeData(bulkContainment.storageTypeId, state)\n }\n\n}\n\nconst getBulkContainmentReviewData = (bulkContainmentId, state) => {\n const bulkContainmentData = getBulkContainmentData(bulkContainmentId, state)\n\n var reviewData = {}\n\n var savedReviewData = dotProp.get(state.firestore, `data.bulkContainmentReviews.${bulkContainmentId}`, {})\n const decisionData = getDecisionData(state).sections[bulkContainmentData.sectionId].bulkContainments\n const requiredFields = getRequiredFields(bulkContainmentData)\n\n return autoReviewData(bulkContainmentData, requiredFields, savedReviewData, decisionData, makeNoScoreObservation, state)\n}\n\n\nconst getWasteStreamIdForBulkContainment = (bulkContainmentId, state) => {\n\n var bulkContainment = getBulkContainmentData(bulkContainmentId, state)\n return _.get(getStorageType(bulkContainment.storageTypeId, state), 'wasteStreamId' )\n}\n\nconst getBulkContainmentsForSection = (sectionId, state) => {\n var sectionData = getSectionDataWithReview(sectionId,state)\n var sectionBulkContainments = sectionData['hasBulkInternalWasteContainment'] === 'yes' ? getAuditBulkContainmentsForSection(sectionId, state) : []\n \n return _(sectionBulkContainments).filter(({storageType, bulkStorageAreaPhoto}) => _.isPresent(storageType) && _.isPresent(bulkStorageAreaPhoto)).map(({id}) => getBulkContainmentData(id, state)).value()\n}\n\nconst getBulkContainmentsForWasteStream = (wasteStreamId, state) => {\n return _.filter(getBulkContainmentsForSection(bulkWasteStorageContainment.sectionId, state), ({id}) => getWasteStreamIdForBulkContainment(id, state) == wasteStreamId)\n}\n\n\nconst getBulkContainmentDataForWasteStream = (wasteStreamId, state) => {\n\n return _.map(getBulkContainmentsForWasteStream(wasteStreamId, state), (bulkContainment)=> {\n\n const title = `${bulkContainment.name} - Storage Area`\n\n const bulkContainmentWithoutComplete = {\n ...bulkContainment,\n title,\n reviewData: getBulkContainmentReviewData(bulkContainment.id, state)\n }\n\n return {\n ...bulkContainmentWithoutComplete,\n isComplete: isComplete(bulkContainmentWithoutComplete, state)\n }\n\n })\n\n}\n\nexport {\n getBulkContainmentReviewData,\n getWasteStreamIdForBulkContainment,\n getBulkContainmentsForSection,\n getBulkContainmentDataForWasteStream\n}\n\n\n","import _ from 'lodashExtended'\nimport dotProp from \"dot-prop-immutable\";\nimport internalWasteContainment from '../components/sectionReviews/InternalWasteContainment'\nimport bulkWasteStorageContainment from '../components/sectionReviews/BulkWasteStorageContainment'\nimport {\n getBulkContainmentsForSection,\n getWasteStreamIdForBulkContainment,\n getBulkContainmentDataForWasteStream\n} from '../bulkContainmentReviews/selectors'\nimport {\n getDecisionData,\n makeObservation,\n autoReviewData,\n getRequiredWasteStreamIds\n} from '../app/selectors'\nimport { getBinsForSection, getBinDataForWasteStream, getWasteStreamIdForBin } from '../binReviews/selectors'\nimport {\n getBulkStorageTypes,\n getStorageType\n} from '../../auditor/app/selectors'\nimport {\n isComplete,\n getCalculatedFields,\n getRequiredFields,\n getReviewResult\n} from '../components/WasteStreamReview'\n\nconst getWasteStreamReviewData = (wasteStream, state) => {\n const savedReviewData = dotProp.get(state.firestore, `data.wasteStreamReviews.${wasteStream.id}`, {})\n const decisionData = getDecisionData(state).sections[wasteStream.sectionId].wasteStreams\n const requiredFields = getRequiredFields(wasteStream)\n\n return autoReviewData(wasteStream, requiredFields, savedReviewData, decisionData, makeObservation, state)\n\n}\n\nconst getWasteStreamsWithReview = (state) => {\n const wasteStreamIds = _([getIdentifiedWasteStreamIds(state), getRequiredWasteStreamIds(state)]).flatten().uniq().value()\n\n return _.map(wasteStreamIds, (wasteStreamId) => {\n const bins = getBinDataForWasteStream(wasteStreamId, state)\n const bulkContainments = getBulkContainmentDataForWasteStream(wasteStreamId, state)\n const storageType = getStorageType(wasteStreamId, state)\n\n\n const wasteStreamWithoutCalculatedFields = {\n id: wasteStreamId,\n name: storageType.name,\n title: `${storageType.name} Stream`,\n sectionId: bulkWasteStorageContainment.sectionId,\n storageType,\n bins,\n bulkContainments\n }\n\n const wasteStreamWithoutReview = {\n ...wasteStreamWithoutCalculatedFields,\n ...getCalculatedFields(wasteStreamWithoutCalculatedFields, state)\n }\n\n\n const wasteStreamWithoutComplete = {\n ...wasteStreamWithoutReview,\n reviewData: getWasteStreamReviewData(wasteStreamWithoutReview, state)\n }\n\n const wasteStreamWithoutResult = {\n isComplete: isComplete(wasteStreamWithoutComplete),\n ...wasteStreamWithoutComplete\n }\n\n return {\n ...wasteStreamWithoutResult,\n reviewResult: getReviewResult(wasteStreamWithoutResult)\n }\n\n })\n\n\n}\n\nconst getWasteStreamIds = (state) => {\n return _.map(getBulkStorageTypes(state), 'id')\n}\n\nconst getIdentifiedWasteStreamIds = (state) => {\n var internalBins = getBinsForSection(internalWasteContainment.sectionId, state)\n var externalBins = getBinsForSection(bulkWasteStorageContainment.sectionId, state)\n\n var bulkContainments = getBulkContainmentsForSection(bulkWasteStorageContainment.sectionId, state)\n\n var foundStorageTypeIds = _([\n _([internalBins, externalBins]).flatten().map(({id}) => getWasteStreamIdForBin(id, state)).value(),\n _(bulkContainments).map(({id}) => getWasteStreamIdForBulkContainment(id, state) ).value(),\n ]).flatten().compact().uniq().value()\n\n //preserve order\n return _(getWasteStreamIds(state)).\n filter((id) => _.includes(foundStorageTypeIds, id)).value()\n\n}\n\n\nexport {\n getWasteStreamReviewData,\n getWasteStreamsWithReview\n}\n","import _ from 'lodashExtended'\nimport dotProp from 'dot-prop-immutable'\nimport {\n getBulkStorageTypes,\n getStorageType,\n getInternalContainerType,\n getBulkStorageType,\n} from '../../auditor/app/selectors'\nimport {\n checkAllDataLoaded,\n sumReviewResults\n} from '../app/selectors'\nimport {\n orderedSectionIds,\n isSectionReviewComplete,\n getSectionReviewResult,\n sectionWeights\n} from '../components/sectionReviews'\nimport { getBinReviewData } from '../binReviews/selectors';\nimport { getBulkContainmentReviewData } from '../bulkContainmentReviews/selectors';\nimport { getSectionDataWithReview } from '../sectionReviews/selectors';\nimport { getWasteStreamsWithReview } from '../wasteStreamReviews/selectors';\nimport { getRoomsWithReview } from '../roomReviews/selectors';\nimport internalWasteContainment from '../components/sectionReviews/InternalWasteContainment'\nimport bulkWasteStorageContainment from '../components/sectionReviews/BulkWasteStorageContainment'\n\nconst getWeightedReviewResult = (sections, state) => {\n\n const reviewResults = _.map(sections, 'reviewResult')\n\n const totalWeightedPercentScore = _(reviewResults).map('weightedPercentScore').compact().sum()\n const score = _(reviewResults).map('score').compact().sum()\n const actionItems = _(reviewResults).map('actionItems').flatten().value()\n\n return {\n totalWeightedPercentScore,\n sectionWeights,\n actionItems,\n }\n\n}\n\nconst getStorageTypeData = (storageTypeId, state) => _.omit(getStorageType(storageTypeId, state), ['exampleInteriorPhotoUrl', 'exampleExteriorPhotoUrl', 'exampleBulkInternalPhotoUrl'])\nconst getContainerTypeData = (containerTypeId, state) => _.omit(getInternalContainerType(containerTypeId, state), ['exampleInteriorPhotoUrl', 'exampleExteriorPhotoUrl'])\n\nconst getAuditReview = (wasteAuditDocumentId, state) => {\n\n if(checkAllDataLoaded(state)) {\n\n var sections = {}\n\n _.each(orderedSectionIds, (sectionId, index) => {\n\n var sectionData = getSectionDataWithReview(sectionId, state)\n\n if(sectionId == internalWasteContainment.sectionId) {\n sectionData.rooms = getRoomsWithReview(state)\n } else if(sectionId == bulkWasteStorageContainment.sectionId) {\n sectionData.wasteStreams = getWasteStreamsWithReview(state)\n }\n\n sections[sectionId] = {\n isComplete: isSectionReviewComplete(sectionData),\n reviewResult: getSectionReviewResult(sectionData),\n ...sectionData\n }\n\n })\n\n const isComplete = _.every(sections, 'isComplete')\n const reviewResult = getWeightedReviewResult(sections, state)\n\n\n const result = {\n sections,\n reviewResult,\n isComplete\n }\n\n console.log(result)\n\n return result\n \n } else {\n\n return null\n }\n}\n\n\nconst scoreToRiskLevel = (score, maxScore) => {\n\n if(score >= 0 && maxScore >= 0) {\n\n var percentScore = maxScore > 0 ? Math.round(score / maxScore * 100.0) : 0\n\n return(percentScore <= 10.0 ? [\"Low\", 'low-risk', percentScore] :\n percentScore <= 40.0 ? [\"Meduim\", 'medium-risk', percentScore] :\n percentScore <= 80.0 ? [\"High\", 'high-risk', percentScore] :\n [\"Severe\", 'severe-risk', percentScore]\n )\n\n } else {\n return [null, 'unknown-risk', null]\n }\n\n}\n\nconst scoreToClass = (score, maxScore) => {\n return(scoreToRiskLevel(score, maxScore)[1])\n}\n\n\nexport {\n getAuditReview,\n scoreToRiskLevel,\n scoreToClass,\n}\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { orderedSectionIds, getSectionTitle } from \"./sectionReviews\";\nimport { useHistory, useParams } from \"react-router-dom\";\nimport classNames from \"classnames\";\nimport CompleteStatusIcon from \"./CompleteStatusIcon\";\nimport { scoreToClass, scoreToRiskLevel } from '../wasteAudit/selectors'\n//import actions from '../slice/actions'\n//var {\n//} = actions\n\nvar SectionReviewNav = ( {\n wasteAudit\n} ) => {\n\n let { sectionId: selectedSectionId } = useParams();\n let history = useHistory();\n\n return(\n \n
\n Audit Navigation\n
\n
\n { _.map(orderedSectionIds, (sectionId) => {\n var { score, maxScore} = _.get(wasteAudit, `sections.${sectionId}.reviewResult`, {})\n return(\n history.push(`/section/${sectionId}`)}\n className={classNames({active: sectionId == selectedSectionId }, \"list-group-item \")}>\n\n \n {getSectionTitle(sectionId)}
\n \n { _.isPresent(score) ? `${score} / ${maxScore}` : null }\n
\n )\n })\n }\n \n
\n )\n}\n\n\n\n\nSectionReviewNav.propTypes = {\n};\n\n\n//const mapStateToProps = (state, {}) => {\n//return {\n//}\n//}\n\n//const mapDispatchToProps = (dispatch, {}) => {\n//return {\n//}\n//}\n\n//SectionReviewSummary = connect(\n//mapStateToProps,\n//mapDispatchToProps\n//)(SectionReviewSummary)\n\n\nexport default SectionReviewNav;\n\n\n\n\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport { Btn } from 'sharedComponents'\n\nvar ScoreSummary = ({\n wasteAudit,\n onSubmitReview\n}) => {\n const {\n reviewResult\n } = wasteAudit\n\n const {\n totalWeightedPercentScore,\n actionItems\n } = reviewResult\n\n return(\n \n
\n Audit Summary\n
\n
\n
\n {Math.round(totalWeightedPercentScore)}% \n Audit Score\n
\n
\n {actionItems.length} \n Actions Identified\n
\n { wasteAudit.isComplete ?
Submit : null }\n
\n
\n )\n}\n\n\nScoreSummary.propTypes = {\n onSubmitReview: PropTypes.func.isRequired\n};\n\n\nexport default ScoreSummary;\n\n\n\n\n\n\n","import React, { useEffect, useState, useLayoutEffect } from \"react\";\nimport { compose } from \"redux\";\nimport dotProp from \"dot-prop-immutable\";\nimport PropTypes from \"prop-types\";\nimport { connect } from \"react-redux\";\nimport { firestoreConnect } from \"react-redux-firebase\";\nimport { Route, Redirect, Switch, useLocation } from \"react-router-dom\";\n//import { Link } from \"sharedComponents\";\nimport { getAuditReview } from \"../wasteAudit/selectors\";\nimport { getDecisionData } from \"../app/selectors\";\nimport { reviewComponentsById } from \"./sectionReviews\";\nimport SectionReviewNav from \"./SectionReviewNav\";\nimport ScoreSummary from \"./ScoreSummary\";\nimport { submitAuditReview } from \"../app/operations\";\nimport StickyBox from \"react-sticky-box\";\n\nfunction mapIt(sections) {\n var sectionTemp = {}\n\n _.each(sections, (x, sectionId) => {\n sectionTemp[sectionId] = {}\n _.each(x, (value, fieldName) => {\n sectionTemp[sectionId][fieldName] = [\n { score: 0, response: 'thisIsAResponse', action: 'thisIsAnAction' },\n ]})\n })\n return sectionTemp\n}\n\nvar App = (props) => {\n const {\n wasteAudit,\n decisionData,\n onSubmitReview,\n } = props\n\n if (wasteAudit) {\n return (\n \n \n
\n \n {\n _.map(reviewComponentsById, (SectionReview, id) => {\n return(\n \n \n )\n }\n )\n }\n \n \n
\n
\n \n \n \n \n \n
\n \n
\n \n );\n } else {\n return (\n \n );\n }\n};\n\nApp.propTypes = {\n wasteAuditDocumentId: PropTypes.string.isRequired,\n};\n\nconst mapStateToProps = (state, props) => {\n const {\n wasteAuditDocumentId,\n } = state.app;\n\n return {\n wasteAuditDocumentId,\n wasteAudit: getAuditReview(wasteAuditDocumentId, state),\n decisionData: getDecisionData(state),\n };\n};\n\nconst mapDispatchToProps = (dispatch, ownProps) => {\n return {\n onSubmitReview: () => dispatch(submitAuditReview())\n };\n};\n\nApp = compose(\n connect(mapStateToProps, mapDispatchToProps),\n firestoreConnect(({ wasteAuditDocumentId }) => {\n return [\n {\n collection: \"waste_audits\",\n doc: wasteAuditDocumentId,\n },\n {\n collection: \"waste_audits\",\n doc: wasteAuditDocumentId,\n subcollections: [{ collection: \"sections\" }],\n storeAs: \"sections\", // make sure to include this\n },\n {\n collection: \"waste_audits\",\n doc: wasteAuditDocumentId,\n subcollections: [{ collection: \"sectionReviews\" }],\n storeAs: \"sectionReviews\", // make sure to include this\n },\n {\n collection: \"waste_audits\",\n doc: wasteAuditDocumentId,\n subcollections: [{ collection: \"rooms\" }],\n storeAs: \"rooms\", // make sure to include this\n orderBy: [\"createdAt\"],\n },\n {\n collection: \"waste_audits\",\n doc: wasteAuditDocumentId,\n subcollections: [{ collection: \"roomReviews\" }],\n storeAs: \"roomReviews\", // make sure to include this\n },\n {\n collection: \"waste_audits\",\n doc: wasteAuditDocumentId,\n subcollections: [{ collection: \"bins\" }],\n storeAs: \"bins\", // make sure to include this\n orderBy: [\"createdAt\"],\n },\n {\n collection: \"waste_audits\",\n doc: wasteAuditDocumentId,\n subcollections: [{ collection: \"binReviews\" }],\n storeAs: \"binReviews\", // make sure to include this\n },\n {\n collection: \"waste_audits\",\n doc: wasteAuditDocumentId,\n subcollections: [{ collection: \"bulkContainments\" }],\n storeAs: \"bulkContainments\", // make sure to include this\n orderBy: [\"createdAt\"],\n },\n {\n collection: \"waste_audits\",\n doc: wasteAuditDocumentId,\n subcollections: [{ collection: \"bulkContainmentReviews\" }],\n storeAs: \"bulkContainmentReviews\", // make sure to include this\n },\n {\n collection: \"waste_audits\",\n doc: wasteAuditDocumentId,\n subcollections: [{ collection: \"wasteStreamReviews\" }],\n storeAs: \"wasteStreamReviews\", // make sure to include this\n }\n ];\n })\n)(App);\n\nexport default App;\n\n","import actions from './actions'\n//import { push } from 'connected-react-router'\n//import _ from 'lodashExtended'\nimport submitToServer from 'submitToServer'\nimport { getAuditReview } from \"../wasteAudit/selectors\";\n\n\nconst submitAuditReview = () => (dispatch, getState, { getFirebase, getFirestore}) => {\n\n const state = getState()\n const submitPath = state.app.submitPath\n const {\n wasteAuditDocumentId,\n } = state.app;\n\n const reviewedAudit = getAuditReview(wasteAuditDocumentId, state)\n\n submitToServer(submitPath, { waste_audit: { reviewedAudit } } ,\n (data,v) => {\n window.location = data.redirect_to\n },\n (data, status) => {\n }, { method: 'PUT' })\n\n console.log('submit')\n}\n\nexport {\n submitAuditReview\n}\n\n\n\n\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\n\nconst {\n} = actions\n\nconst reducer = createReducer({\n},\n{})\n\nexport default reducer\n\n","import { createAction } from 'redux-act';\n\n\nexport default {\n}\n\n","import reducer from './reducer'\n\nexport { default as appActions } from \"./actions\";\n\nexport default reducer\n","import dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\nimport { firebaseReducer } from 'react-redux-firebase'\nimport appReducer from './app'\nimport { connectRouter } from 'connected-react-router'\nimport { firestoreReducer } from 'redux-firestore';\n\nconst createRootReducer = (history) => {\n\n\n const routerReducer = connectRouter(history)\n\n const reducer = (state = {}, action) => {\n return {\n ...state,\n app: appReducer(state.app, action),\n firestore: firestoreReducer(state.firestore, action),\n firebase: firebaseReducer(state.firebase, action),\n router: routerReducer(state.router, action)\n }\n\n }\n\n\n return reducer\n\n}\n\nexport default createRootReducer\n\n","import { createStore, applyMiddleware } from 'redux';\nimport createRootReducer from './reducer'\nimport thunk from 'redux-thunk'\nimport { routerMiddleware } from 'connected-react-router'\nimport { composeWithDevTools } from 'redux-devtools-extension';\nimport { reduxFirestore, getFirestore } from 'redux-firestore';\nimport { getFirebase } from 'react-redux-firebase'\nimport { createHashHistory } from 'history'\nimport appActions from './app/actions'\n\nexport const history = createHashHistory()\n\nexport default function configureStore(initialState, firebase) {\n\n const rootReducer = createRootReducer(history)\n\n\n const store = createStore(rootReducer,\n initialState,\n composeWithDevTools(\n applyMiddleware(\n routerMiddleware(history),\n thunk.withExtraArgument({getFirestore, getFirebase})\n ),\n reduxFirestore(firebase)\n ));\n\n\n var connectedRef = firebase.database().ref(\".info/connected\");\n\n firebase.firestore().enablePersistence()\n .catch((error) => {\n if (error === \"failed-precondition\") {\n alert(\"Multiple tabs open, offline data only works in one tab at a a time.\")\n } else if (error === \"unimplemented\") {\n alert(\"Cannot save offline on this browser.\")\n }\n });\n\n if (module.hot) {\n module.hot.accept('./reducer', () => {\n const nextRootReducer = createRootReducer(history)\n store.replaceReducer(nextRootReducer);\n });\n }\n\n return store;\n\n}\n","import React from \"react\"\nimport { Provider } from 'react-redux';\nimport { RootNode, configureStore, history } from '../apps/audit-review'\nimport firebase from 'firebase/app'\nimport 'firebase/auth';\nimport 'firebase/database';\nimport 'firebase/firestore';\nimport 'firebase/storage';\nimport { ReactReduxFirebaseProvider } from 'react-redux-firebase';\nimport { createFirestoreInstance } from 'redux-firestore'\nimport { ConnectedRouter } from 'connected-react-router'\nimport 'react-router-modal/css/react-router-modal.css'\nimport { ModalContainer } from 'react-router-modal';\n\nconst rrfConfig = { useFirestoreForStorageMeta: true } \n\nexport default ({initialState, fbConfig}) => {\n firebase.initializeApp(fbConfig)\n\n\n const store = configureStore(initialState, firebase)\n\n return (\n \n \n \n \n \n \n
\n \n \n \n );\n}\n\n\n\n","import _ from 'lodashExtended'\n\nconst getDisputeLedgerItem = (id, state) => {\n return state.disputeLedgerItems.byId[id]\n}\n\nconst getDisputeLedgerItems = (state) => {\n return Object.values(state.disputeLedgerItems.byId)\n}\n\nconst getDisputeLedgerItemsById = (state) => {\n return state.disputeLedgerItems.byId\n}\n\nconst getDisputeLedgerItemsForVendorCredit = (vendorCreditId, state) => {\n return _.filter(getDisputeLedgerItems(state), { vendorCreditId })\n}\nconst getDisputeLedgerItemsForVendorInvoice = (vendorInvoiceId, state) => {\n return _.filter(getDisputeLedgerItems(state), { vendorInvoiceId })\n}\n\nconst getDisputeLedgerItemsByInvoiceId = (state) => {\n return _.groupBy(getDisputeLedgerItems(state), 'vendorInvoiceId')\n}\n\n\nexport {\n getDisputeLedgerItem,\n getDisputeLedgerItems,\n getDisputeLedgerItemsById,\n getDisputeLedgerItemsForVendorCredit,\n getDisputeLedgerItemsForVendorInvoice,\n getDisputeLedgerItemsByInvoiceId\n}\n","import _ from \"lodashExtended\";\n\nconst getVendorCreditAllocations = state => {\n return Object.values(state.vendorCreditAllocations.byId);\n};\n\nconst getVendorCreditAllocationsByInvoiceId = state => {\n return _.groupBy(state.vendorCreditAllocations.byId, \"vendorInvoiceId\");\n};\n\nconst getVendorCreditAllocationsForInvoiceId = (vendorInvoiceId, state) => {\n return _.filter(state.vendorCreditAllocations.byId, { vendorInvoiceId });\n};\n\nconst getVendorCreditAllocationsForCreditId = (vendorCreditId, state) => {\n return _(state.vendorCreditAllocations.byId)\n .reject({ _destroy: \"1\" })\n .filter({ vendorCreditId })\n .value();\n};\n\nconst getVendorCreditAllocationByInvoiceAndCreditId = (\n vendorInvoiceId,\n vendorCreditId,\n state\n) => {\n return _(state.vendorCreditAllocations.byId)\n .reject({ _destroy: \"1\" })\n .find({ vendorInvoiceId, vendorCreditId });\n};\n\nconst getAllVendorCreditAllocationsForCreditId = (vendorCreditId, state) => {\n return _(state.vendorCreditAllocations.byId)\n .filter({ vendorCreditId })\n .value();\n};\n\nexport {\n getVendorCreditAllocations,\n getVendorCreditAllocationsByInvoiceId,\n getVendorCreditAllocationsForInvoiceId,\n getVendorCreditAllocationByInvoiceAndCreditId,\n getVendorCreditAllocationsForCreditId,\n getAllVendorCreditAllocationsForCreditId\n};\n","const getVendorInvoice = (id, state) => {\n return state.vendorInvoices.byId[id]\n}\n\nconst getVendorInvoices = (state) => {\n return Object.values(state.vendorInvoices.byId)\n}\n\nconst getVendorInvoicesById = (state) => {\n return state.vendorInvoices.byId\n}\n\n\nexport {\n getVendorInvoice,\n getVendorInvoices,\n getVendorInvoicesById\n}\n","import _ from 'lodashExtended'\nimport { getAllocationSummary, getGrossCreditBalanceCents } from '../vendorCredit/selectors'\nimport { getVendorInvoice } from '../vendorInvoices/selectors'\n\nconst getShowAllInvoices = (state) => {\n return state.app.showAllInvoices\n}\n\nconst getMode = (state) => {\n return state.app.mode\n}\n\nconst getSelectedInvoiceId = (state) => {\n return state.app.selectedInvoiceId\n}\n\nconst canSubmit = (state) => {\n return(getGrossCreditBalanceCents(state) >= 0 &&\n _.every(getAllocationSummary(state), ({grossBalanceCents}, vendorInvoiceId) => grossBalanceCents >= 0 ))\n}\n\nconst getSelectedInvoiceAllocationSummary = (state) => {\n return getAllocationSummary(state)[getSelectedInvoiceId(state)]\n}\n\nconst getSelectedInvoice = (state) => {\n return getVendorInvoice(getSelectedInvoiceId(state), state)\n}\n\nexport {\n getShowAllInvoices,\n getMode,\n getSelectedInvoiceId,\n canSubmit,\n getSelectedInvoiceAllocationSummary,\n getSelectedInvoice\n}\n","import _ from 'lodashExtended'\nimport { getDisputeLedgerItemsForVendorCredit, getDisputeLedgerItemsByInvoiceId } from '../disputeLedgerItems/selectors'\nimport { getVendorCreditAllocationsForCreditId, getVendorCreditAllocationsByInvoiceId } from '../vendorCreditAllocations/selectors'\nimport { getSelectedInvoiceId } from '../app/selectors'\nimport { getVendorInvoice } from '../vendorInvoices/selectors'\n\nconst getVendorCredit = (state) => {\n return state.vendorCredit\n}\n\nconst getAllocationSummary = (state) => {\n const { id: vendorCreditId } = getVendorCredit(state)\n const disputeLedgerItemsByInvoiceId = getDisputeLedgerItemsByInvoiceId(state)\n const creditAllocationsByInvoiceId = getVendorCreditAllocationsByInvoiceId(state)\n const vendorInvoiceIds = _([\n _.map(getDisputeLedgerItemsForVendorCredit(vendorCreditId, state), 'vendorInvoiceId'),\n _.map(getVendorCreditAllocationsForCreditId(vendorCreditId, state), 'vendorInvoiceId'),\n getSelectedInvoiceId(state) ]).flatten().compact().uniq().value()\n\n var summary = {}\n\n _.each(vendorInvoiceIds, (id) => {\n var x = getVendorInvoice\n const { grossTotalCents } = x(id, state)\n\n\n const thisNoteCreditAllocations = _(creditAllocationsByInvoiceId[id] || []).filter({vendorCreditId}).reject({_destroy: '1'}).value()\n const thisNoteResolvedDisputes = _(disputeLedgerItemsByInvoiceId[id] || []).filter({vendorCreditId}).value()\n\n\n const thisNoteGrossResolvedDisputeCents = _(thisNoteResolvedDisputes).map('grossTotalCents').sum()\n const thisNoteGrossCreditAllocationCents = _(thisNoteCreditAllocations).map('grossTotalCents').sum()\n const thisNoteGrossTotalCreditCents = thisNoteGrossResolvedDisputeCents + thisNoteGrossCreditAllocationCents\n const thisNoteNetTotalCreditCents = Math.round(thisNoteGrossTotalCreditCents / 1.20)\n\n const otherNoteGrossResolvedDisputeCents = _(disputeLedgerItemsByInvoiceId[id] || []).filter(({vendorCreditId: itemVendorCreditId}) => _.isPresent(itemVendorCreditId) && itemVendorCreditId != vendorCreditId).map('grossTotalCents').sum()\n const otherNoteGrossCreditAllocationCents = _(creditAllocationsByInvoiceId[id] || []).filter(({vendorCreditId: itemVendorCreditId}) => _.isPresent(itemVendorCreditId) && itemVendorCreditId != vendorCreditId).map('grossTotalCents').sum()\n const otherNoteGrossTotalCreditCents = otherNoteGrossResolvedDisputeCents + otherNoteGrossCreditAllocationCents\n\n const grossDisputeTotal = _(disputeLedgerItemsByInvoiceId[id] || []).map('grossTotalCents').sum()\n\n const grossTotalCreditCents = otherNoteGrossTotalCreditCents + thisNoteGrossTotalCreditCents\n const grossBalanceCents = grossTotalCents - grossTotalCreditCents\n\n const openToAllocateGrossBalanceCents = grossTotalCents - otherNoteGrossTotalCreditCents - thisNoteGrossResolvedDisputeCents\n const openToResolveDisputeGrossBalanceCents = grossDisputeTotal - otherNoteGrossResolvedDisputeCents\n\n const hasCreditAllocationError = _.some(thisNoteCreditAllocations, ({errors}) => _.isPresent(errors))\n const hasResolvedDisputeError = _.some(thisNoteResolvedDisputes, ({errors}) => _.isPresent(errors))\n\n summary[id] = {\n vendorInvoiceId: id,\n grossTotalCents,\n thisNoteGrossResolvedDisputeCents,\n thisNoteGrossCreditAllocationCents,\n grossTotalCreditCents,\n grossBalanceCents,\n grossDisputeTotal,\n otherNoteGrossTotalCreditCents,\n thisNoteGrossTotalCreditCents,\n thisNoteNetTotalCreditCents,\n openToAllocateGrossBalanceCents,\n openToResolveDisputeGrossBalanceCents,\n hasCreditAllocationError,\n hasResolvedDisputeError,\n hasValidationError: hasCreditAllocationError || hasResolvedDisputeError,\n thisNoteCreditAllocations,\n thisNoteResolvedDisputes\n }\n })\n\n //console.log(summary)\n return summary\n\n}\n\nconst getGrossCreditBalanceCents = (state) => {\n const vendorCredit = getVendorCredit(state)\n const creditAllocations = getVendorCreditAllocationsForCreditId(vendorCredit.id, state)\n const allocatedGrossTotalCents = _(creditAllocations).map('grossTotalCents').sum()\n const resolvedGrossTotalCents = _(getDisputeLedgerItemsForVendorCredit(vendorCredit.id, state)).map('grossTotalCents').sum()\n const grossCreditBalanceCents = vendorCredit.grossTotalCents - (allocatedGrossTotalCents + resolvedGrossTotalCents)\n\n return grossCreditBalanceCents\n}\n\nexport {\n getVendorCredit,\n getAllocationSummary,\n getGrossCreditBalanceCents\n}\n","import { createAction } from 'redux-act';\n\nconst disputesLoaded = createAction(\"disputes loaded for invoice\", (vendorInvoiceId) => { return({ vendorInvoiceId }) });\n\nexport default {\n disputesLoaded,\n}\n\n","import { createAction } from 'redux-act';\n\nconst updateCreditAllocation = createAction(\"set allocated credit args\", (vendorInvoiceId, vendorCreditId, args) => { return( { vendorInvoiceId, vendorCreditId, args } ) });\nconst markForDestroy = createAction(\"mark for destroy the allocated credit\", (id) => { return( { id } ) });\nconst updateFromServer = createAction(\"update allocations from server\");\n\nexport default {\n updateCreditAllocation,\n markForDestroy,\n updateFromServer\n}\n\n","import { createAction } from 'redux-act';\n\nconst setVendorCreditId = createAction(\"set dispute credit note\", (ids, vendorCreditId) => { return( { ids, vendorCreditId } ) });\nconst loadSuccess = createAction(\"dispute item has been loaded success from server\", (loadedDisputeLedgerItems) => { return( { loadedDisputeLedgerItems } ) });\n\nexport default {\n setVendorCreditId,\n loadSuccess\n}\n\n","import actions from './actions'\nimport {checkDisputesLoaded} from './selectors'\nimport vendorCreditAllocationActions from '../vendorCreditAllocations/actions'\nimport submitToServer from 'submitToServer'\nimport { getDisputeLedgerItemsForVendorCredit } from '../disputeLedgerItems/selectors'\nimport disputeLedgerItemsActions from '../disputeLedgerItems/actions'\nimport { getVendorCredit } from '../vendorCredit/selectors'\nimport { getAllVendorCreditAllocationsForCreditId } from '../vendorCreditAllocations/selectors'\nimport { prepareSubmitData } from 'sharedUtils'\nimport _ from 'lodashExtended'\n\nconst submitVendorCredit = () => (dispatch, getState) => {\n const state = getState()\n const vendorCreditPath = state.api.vendorCreditPath\n const vendorCredit = getVendorCredit(state)\n\n var submitData = {\n disputeLedgerItemIds: _.map(getDisputeLedgerItemsForVendorCredit(vendorCredit.id, state), 'id'),\n vendorCreditAllocations: getAllVendorCreditAllocationsForCreditId(vendorCredit.id, state)\n }\n\n submitToServer(vendorCreditPath, { vendorCredit: prepareSubmitData(submitData, ['vendorCreditAllocations']) },\n (data,v) => {\n location.href = vendorCreditPath\n },\n (data, status) => {\n if(status == 422) {\n dispatch(vendorCreditAllocationActions.updateFromServer(_.values(data.vendorCreditAllocations.byId)))\n } else {\n alert(`There was an issue with the server, Please contact support, support@anenta.com (status: ${status})`)\n }\n }, { method: 'PUT' })\n}\n\nconst loadDisputeLedgerItems = (vendorInvoiceId) => (dispatch, getState) => {\n const state = getState()\n\n if(!checkDisputesLoaded(vendorInvoiceId, state)) {\n\n const path = state.api.disputeLedgerItemsPath + \"?\" + $.param({vendor_invoice_ids: [vendorInvoiceId]})\n\n submitToServer(path, '',\n (data,v) => {\n dispatch(actions.disputesLoaded(vendorInvoiceId))\n\n if(data.disputeLedgerItems) {\n dispatch(disputeLedgerItemsActions.loadSuccess(data.disputeLedgerItems.byId))\n }\n },\n (data, status) => {\n data\n alert(`There was an issue with the server, Please contact support, support@anenta.com (status: ${status})`)\n }, { method: 'GET' }\n )\n }\n}\n\nexport {\n submitVendorCredit,\n loadDisputeLedgerItems\n}\n","import _ from 'lodashExtended'\n\nconst checkDisputesLoaded = (vendorInvoiceId, state) => {\n return _.includes(state.api.loadedDisputeInvoiceIds, vendorInvoiceId)\n}\n\nexport {\n checkDisputesLoaded\n}\n","import { createAction } from 'redux-act';\n\nconst setShowAllInvoices = createAction(\"set showAllInvoices filter\");\nconst setMode = createAction(\"set mode\");\nconst setSelectedInvoice = createAction(\"set selected invoice\");\n\nexport default {\n setShowAllInvoices,\n setMode,\n setSelectedInvoice,\n}\n\n","import actions from './actions'\nimport { loadDisputeLedgerItems } from '../api/operations'\nimport submitToServer from 'submitToServer'\n\nconst selectInvoice = (vendorInvoiceId) => (dispatch, getState) => {\n const state = getState()\n\n dispatch(loadDisputeLedgerItems(vendorInvoiceId))\n dispatch(actions.setSelectedInvoice(vendorInvoiceId))\n\n}\n\nexport {\n selectInvoice\n}\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport { connect } from 'react-redux';\nimport _ from 'lodashExtended';\nimport { getAllocationSummary } from '../vendorCredit/selectors'\nimport { getSelectedInvoiceId } from '../app/selectors'\nimport { getVendorInvoicesById } from '../vendorInvoices/selectors'\nimport { Table } from 'react-bootstrap';\nimport { hMoney } from 'sharedFormatters'\nimport { Link, Btn } from 'sharedComponents'\nimport { selectInvoice} from '../app/operations'\n//import actions from '../slice/actions'\n//var {\n//} = actions\n\nvar Summary = ( { summaryData, vendorInvoicesById, selectedInvoiceId, onSelectInvoice } ) => {\n\n const otherNoteCreditCents = _(summaryData).map('otherNoteGrossTotalCreditCents').sum()\n\n var rows = _(summaryData).sortBy(({vendorInvoiceId}) => vendorInvoicesById[vendorInvoiceId].number).map(({\n grossTotalCents,\n hasValidationError,\n thisNoteGrossTotalCreditCents,\n thisNoteNetTotalCreditCents,\n otherNoteGrossTotalCreditCents,\n grossBalanceCents,\n vendorInvoiceId}) => {\n var { number } = vendorInvoicesById[vendorInvoiceId]\n return(\n \n {number} \n {hMoney(grossTotalCents)} \n {hMoney(thisNoteGrossTotalCreditCents)} \n { otherNoteCreditCents > 0 ? {hMoney(otherNoteCreditCents)} : null }\n {hMoney(thisNoteNetTotalCreditCents)} \n {hMoney(grossBalanceCents)} \n \n { hasValidationError ? : null }\n { selectedInvoiceId != vendorInvoiceId ? onSelectInvoice(vendorInvoiceId)}>{ hasValidationError ? 'Error' : 'View'} : \"Selected\"}\n \n \n )}).value()\n\n return(\n \n
\n \n \n Inv # \n Gross Total \n Allocated (G) \n { otherNoteCreditCents > 0 ? Other Credits (G) : null }\n Allocated (N) \n Gross Balance \n Actions \n \n \n \n {rows}\n \n
\n
\n )\n}\n\n\nSummary.propTypes = {\n};\n\n\nconst mapStateToProps = (state, {}) => {\n return {\n summaryData: getAllocationSummary(state),\n vendorInvoicesById: getVendorInvoicesById(state),\n selectedInvoiceId: getSelectedInvoiceId(state),\n }\n}\n\nconst mapDispatchToProps = (dispatch, {}) => {\n return {\n onSelectInvoice: (invoiceId) => { dispatch(selectInvoice(invoiceId))},\n }\n}\n\nSummary = connect(\n mapStateToProps,\n mapDispatchToProps\n)(Summary)\n\n\nexport default Summary;\n\n\n\n\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport { connect } from 'react-redux';\nimport _ from 'lodashExtended';\nimport classNames from 'classnames';\nimport { getVendorCreditAllocationByInvoiceAndCreditId } from '../vendorCreditAllocations/selectors'\nimport { Btn, ModelErrors } from 'sharedComponents'\nimport { hMoney } from 'sharedFormatters'\nimport actions from '../vendorCreditAllocations/actions'\nimport { getVendorCredit, getGrossCreditBalanceCents } from '../vendorCredit/selectors'\nimport { getSelectedInvoiceAllocationSummary } from '../app/selectors'\n\nvar {\n updateCreditAllocation\n} = actions\n\n\nconst eventToArgs = (event) => {\n const target = event.target;\n const value = target.type === 'checkbox' ? target.checked : target.value;\n const name = target.name;\n return({\n [name]: value\n })\n}\n\nvar TextAreaInput = ({allErrors = {}, value, onChange, label, name, optional = false, placeholder }) => {\n let errors = _.uniq(allErrors[name] || [])\n let hasError = _.isPresent(errors)\n return (\n \n
{label} \n
\n {_.map(errors, (error) =>
{error}
) }\n
\n )\n\n}\n\nvar TextInput = ({allErrors = {}, value, onChange, label, name, optional = false }) => {\n let errors = _.uniq(allErrors[name] || [])\n let hasError = _.isPresent(errors)\n return (\n \n
{label} \n
onChange(eventToArgs(e))} name={name}/>\n {_.map(errors, (error) =>
{error}
) }\n
\n )\n}\n\n\nclass CreditAllocationForm extends React.Component {\n\n constructor(props) {\n super(props);\n this.state = {\n getToNetGrossCents: null,\n getToNetTotalCents: null,\n }\n this.handleInputChange = this.handleInputChange.bind(this);\n this.handleGetToNetChange = this.handleGetToNetChange.bind(this);\n }\n\n handleInputChange(args) {\n this.props.onUpdate(_.pick(args, ['grossTotal', 'creditReason']))\n //this.setState(args, (x) => {\n //this.props.onUpdate(_.pick(this.state, ['grossTotal', 'creditReason']))\n //});\n }\n\n handleGetToNetChange({getToNetTotal}) {\n var getToNetTotalFloat = parseFloat(getToNetTotal)\n var getToNetGrossFloat = isNaN(getToNetTotalFloat) ? null : (getToNetTotalFloat * 1.2)\n var getToNetTotalCents = isNaN(getToNetTotalFloat) ? null : Math.round(getToNetTotalFloat * 100)\n var getToNetGrossCents = getToNetGrossFloat ? Math.round(getToNetGrossFloat * 100) : null\n\n this.setState({getToNetGrossCents, getToNetTotalCents})\n //this.setState(args, (x) => {\n //this.props.onUpdate(_.pick(this.state, ['grossTotal', 'creditReason']))\n //});\n }\n\n //static getDerivedStateFromProps(nextProps, prevState) {\n //if(nextProps.id != prevState.recordId) {\n //return {\n //recordId: nextProps.id,\n //grossTotal: nextProps.grossTotal,\n //creditReason: nextProps.creditReason\n //}\n //} else {\n //return null\n //}\n //}\n\n render() {\n var { id, grossTotal = '', creditReason = '', grossTotalCents = 0, getToNetTotal, grossResolvedDisputeCents, errors, grossInvoiceBalanceCents, grossCreditBalanceCents, onUpdate, onDelete } = this.props\n const { getToNetGrossCents, getToNetTotalCents } = this.state\n var applyGetToNetGrossCents\n\n if(getToNetGrossCents) {\n applyGetToNetGrossCents = getToNetGrossCents - grossResolvedDisputeCents\n }\n\n const [ maxApplyCents, maxApplyText ] = _([\n [grossInvoiceBalanceCents + grossTotalCents, 'Apply Invoice Balance'],\n [grossCreditBalanceCents + grossTotalCents, 'Apply Credit Balance']\n ]).minBy(([x,y]) => x)\n\n return(\n \n
\n \n
\n
\n
\n
\n
\n { id ? onDelete(id)}>Remove : null }\n
\n { maxApplyCents != 0 ?
this.handleInputChange({grossTotal: maxApplyCents / 100.0}) }>{maxApplyText} {hMoney(maxApplyCents)} : null } \n { applyGetToNetGrossCents && applyGetToNetGrossCents != 0 ?
this.handleInputChange({grossTotal: applyGetToNetGrossCents / 100.0}) }>Apply to get to Net {hMoney(getToNetTotalCents)} : null }\n
\n
\n
\n \n \n \n
\n
\n \n
\n
\n )\n }\n}\n\n\nCreditAllocationForm.propTypes = {\n vendorInvoiceId: PropTypes.number.isRequired,\n vendorCreditId: PropTypes.number.isRequired\n};\n\n\nconst mapStateToProps = (state, { vendorInvoiceId, vendorCreditId }) => {\n const { grossBalanceCents: grossInvoiceBalanceCents, thisNoteGrossResolvedDisputeCents: grossResolvedDisputeCents} = getSelectedInvoiceAllocationSummary(state)\n const grossCreditBalanceCents = getGrossCreditBalanceCents(state)\n\n return {\n grossInvoiceBalanceCents,\n grossCreditBalanceCents,\n grossResolvedDisputeCents,\n ...getVendorCreditAllocationByInvoiceAndCreditId(vendorInvoiceId, vendorCreditId, state)\n }\n}\n\nconst mapDispatchToProps = (dispatch, { vendorInvoiceId, vendorCreditId }) => {\n return {\n onUpdate: (args) => dispatch(actions.updateCreditAllocation(vendorInvoiceId, vendorCreditId, args )),\n onDelete: (id) => dispatch(actions.markForDestroy(id)),\n }\n}\n\n\nCreditAllocationForm = connect(\n mapStateToProps,\n mapDispatchToProps\n)(CreditAllocationForm)\n\n\nexport default CreditAllocationForm;\n\n\n\n\n\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport { connect } from 'react-redux';\nimport _ from 'lodashExtended';\nimport { Table } from 'react-bootstrap';\nimport { getVendorCredit } from '../vendorCredit/selectors'\nimport { hMoney } from 'sharedFormatters'\nimport { getDisputeLedgerItemsForVendorInvoice } from '../disputeLedgerItems/selectors'\nimport { resolveDispute } from '../disputeLedgerItems/operations'\nimport { getSelectedInvoiceId } from '../app/selectors'\nimport { CheckBoxWithLabel, Link, Btn } from 'sharedComponents'\n//import actions from '../slice/actions'\n//var {\n//} = actions\n\nvar DisputeResolveForm = ( { disputeLedgerItems, vendorCreditId, onResolveDispute} ) => {\n\n\n const selectableItemIds = _(disputeLedgerItems).filter(({vendorCreditId: disputeItemVendorCreditId}) => vendorCreditId == disputeItemVendorCreditId || _.isBlank(disputeItemVendorCreditId)).map('id').value()\n\n var rows = _(disputeLedgerItems).orderBy('vendorLocationCode', 'date').map(({id, date, serviceCode,\n vendorServiceCode, vendorLocationCode, grossTotalCents, quantity, unitPriceCents,\n reason, netTotalCents, locationName, vendorCreditId: disputeItemVendorCreditId }) => {\n return(\n \n {moment(date).format(\"ddd, DD MMM YYYY\")} \n {locationName} \n {serviceCode} \n {vendorServiceCode} \n {vendorLocationCode} \n {quantity} \n {hMoney(unitPriceCents)} \n {hMoney(netTotalCents)} \n {hMoney(grossTotalCents)} \n {reason} \n \n { _.includes(selectableItemIds, id) ?\n onResolveDispute(id, isResolved) }> \n : Credited Via {disputeItemVendorCreditId} }\n \n \n )}).value()\n\n return(\n \n
\n
\n onResolveDispute(selectableItemIds, false)}>De-Select All \n onResolveDispute(selectableItemIds, true)}>Select All \n
\n
\n \n \n Date \n Location \n VLC \n Anenta Service \n Vendor Service \n Quantity \n Unit \n Net Total \n Gross Total \n Reason \n Select \n \n \n \n {rows}\n \n
\n
\n
\n )\n}\n\nDisputeResolveForm.propTypes = {\n vendorInvoiceId: PropTypes.number.isRequired,\n vendorCreditId: PropTypes.number.isRequired\n};\n\n\nconst mapStateToProps = (state, { vendorInvoiceId } ) => {\n return {\n disputeLedgerItems: getDisputeLedgerItemsForVendorInvoice(vendorInvoiceId, state),\n }\n}\n\nconst mapDispatchToProps = (dispatch, { vendorCreditId }) => {\n return {\n onResolveDispute: (disputeLedgerItemId, isResolved) => dispatch(resolveDispute(disputeLedgerItemId, vendorCreditId, isResolved))\n }\n}\n\nDisputeResolveForm = connect(\n mapStateToProps,\n mapDispatchToProps\n)(DisputeResolveForm)\n\n\nexport default DisputeResolveForm;\n\n\n\n\n\n\n","import actions from './actions'\nimport { getVendorCreditAllocations } from '../vendorCreditAllocations/selectors'\nimport { getDisputeLedgerItemsForVendorCredit, getDisputeLedgerItems, getDisputeLedgerItem } from './selectors'\nimport { getVendorCredit } from '../vendorCredit/selectors'\n\nconst resolveDispute = (disputeLedgerItemIds, vendorCreditId, isResolved) => (dispatch, getState) => {\n const state = getState()\n dispatch(actions.setVendorCreditId(disputeLedgerItemIds, isResolved ? vendorCreditId : null))\n}\n\nexport {\n resolveDispute\n}\n\n","import React from 'react';\nimport PropTypes from \"prop-types\"\nimport { connect } from 'react-redux';\nimport { Alert } from 'react-bootstrap'\nimport { hMoney } from 'sharedFormatters'\nimport { getVendorCredit, getGrossCreditBalanceCents } from '../vendorCredit/selectors'\n\n\n//import { DropdownSelect, DateSelect, ModelErrors, Link } from 'sharedComponents'\n//import actions from '../slice/actions'\n//var {\n//} = actions\n\nvar CreditBalanceAlert = ( { grossCreditBalanceCents, vendorCredit } ) => {\n\n if(grossCreditBalanceCents < 0) {\n return(\n \n You have gone over the available credit! {hMoney(vendorCredit.grossTotalCents)} \n The current balance is {hMoney(grossCreditBalanceCents)}
\n \n )\n } else if(grossCreditBalanceCents == 0) {\n return(\n All credit used! {hMoney(vendorCredit.grossTotalCents)} \n There is no credit left to allocate on this note
\n \n )\n } else if (grossCreditBalanceCents > 0){\n return(\n \n Credit remaining {hMoney(grossCreditBalanceCents)} \n \n )\n }\n}\n\n\n\nCreditBalanceAlert.propTypes = {\n};\n\n\nconst mapStateToProps = (state, {}) => {\n return {\n vendorCredit: getVendorCredit(state),\n grossCreditBalanceCents: getGrossCreditBalanceCents(state)\n }\n}\n\nconst mapDispatchToProps = (dispatch, {}) => {\n return {\n }\n}\n\nCreditBalanceAlert = connect(\n mapStateToProps,\n mapDispatchToProps\n)(CreditBalanceAlert)\n\n\nexport default CreditBalanceAlert;\n\n\n\n\n\n\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport Select from 'react-select'\nimport { connect } from 'react-redux';\nimport _ from 'lodashExtended'\nimport { PDFObject } from 'react-pdfobject'\nimport { getVendorCredit, getAllocationSummary } from '../vendorCredit/selectors'\nimport { getVendorInvoices } from '../vendorInvoices/selectors'\nimport { submitVendorCredit } from '../api/operations'\nimport { getShowAllInvoices, getMode, getSelectedInvoiceId, getSelectedInvoice, canSubmit, getSelectedInvoiceAllocationSummary } from '../app/selectors'\nimport { hMoney } from 'sharedFormatters'\nimport { Link, CheckBoxWithLabel, Btn } from 'sharedComponents'\nimport appActions from '../app/actions'\nimport { selectInvoice } from '../app/operations'\nimport Summary from './Summary'\nimport CreditAllocationForm from './CreditAllocationForm'\nimport DisputeResolveForm from './DisputeResolveForm'\nimport CreditBalanceAlert from './CreditBalanceAlert'\n\nconst filterOptions = (candidate, input) => {\n input = _.lowerCase(_.trim(input))\n candidate\n input\n if(_.isBlank(input)) {\n return true\n } else {\n return _.lowerCase(candidate.data.searchLabel).indexOf(input) > -1;\n }\n};\n\n\nconst getOption = ({id, number, billingPeriodMonth, grossTotalCents, inDisputeGrossTotalCents}) => {\n const searchLabel = `${number} - ${billingPeriodMonth} ${inDisputeGrossTotalCents > 0 ? `dispute ${hMoney(inDisputeGrossTotalCents)}` : ''}`\n return { searchLabel, label: {number} - {billingPeriodMonth} {hMoney(grossTotalCents)} {inDisputeGrossTotalCents > 0 ? (in dispute {hMoney(inDisputeGrossTotalCents)}) : ''} , value: id }\n}\n\n\nvar App = ({vendorCredit, canSubmit, vendorInvoices, selectedInvoice, showAllInvoices, hasAnyValidationError,\n mode, selectedInvoiceAllocationSummary, onSelectInvoice, onSetShowAllInvoices, onSave, onSetMode, ...restProps}) => {\n var invoiceSelectOptions, invoiceSelectPlaceholder, form, allSelectOptions\n var selectedInvoiceOption = null\n\n const { hasValidationError, hasCreditAllocationError, thisNoteGrossCreditAllocationCents, thisNoteGrossResolvedDisputeCents, openToAllocateGrossBalanceCents, openToResolveDisputeGrossBalanceCents } = selectedInvoiceAllocationSummary || {}\n\n if(showAllInvoices) {\n allSelectOptions = []\n invoiceSelectOptions = _(vendorInvoices).groupBy('vendorAccountName').map((invoices, vendorAccountName) => {\n const options = _(invoices).sortBy('billingPeriodMonthId').map((item) => {\n return getOption(item)\n }).value()\n\n allSelectOptions = allSelectOptions.concat(options)\n\n return {\n label: vendorAccountName,\n options\n }\n }).value()\n\n invoiceSelectPlaceholder = 'Select from all Invoices'\n } else {\n invoiceSelectOptions = _(vendorInvoices).filter(({vendorAccountId}) => vendorAccountId == vendorCredit.vendorAccountId ).sortBy('billingPeriodMonthId').map((item) => {\n return getOption(item)\n }).value()\n invoiceSelectPlaceholder = `Select Invoice from ${vendorCredit.vendorAccountName}`\n allSelectOptions = invoiceSelectOptions\n }\n\n if(selectedInvoice) {\n selectedInvoiceOption = _.find(allSelectOptions, {value: selectedInvoice.id})\n\n if(mode == 'credit-allocation') {\n form = \n } else if(mode == 'dispute-resolution') {\n form = \n }\n }\n\n return(\n \n
\n
\n
\n
\n Vendor Account {vendorCredit.vendorAccountName} \n
\n
\n Gross Total {hMoney(vendorCredit.grossTotalCents)} \n
\n
\n
\n
\n
{hasAnyValidationError ? 'Error' : 'Save'} \n
\n
i\n { vendorCredit.scanUrl ?
: null }\n
\n
\n
\n
\n \n
\n
\n
\n Credit applies to other accounts \n
\n
onSelectInvoice(value) } name=\"invoice\" placeholder={invoiceSelectPlaceholder} />\n \n
\n \n
\n
\n { selectedInvoiceAllocationSummary ?\n
\n
\n onSetMode('credit-allocation')}>Apply to the remaining balance ({hMoney(thisNoteGrossCreditAllocationCents)} / {hMoney(openToAllocateGrossBalanceCents)}) \n
\n
\n onSetMode('dispute-resolution')}>Apply against disputes ({hMoney(thisNoteGrossResolvedDisputeCents)} / {hMoney(openToResolveDisputeGrossBalanceCents)}) \n
\n
: null }\n {form}\n
\n )\n}\n\nApp.propTypes = {\n\n}\n\nconst mapStateToProps = (state, props) => {\n\n\n const selectedInvoiceId = getSelectedInvoiceId(state)\n const allocationSummary = getAllocationSummary(state)\n const selectedInvoiceAllocationSummary = allocationSummary[selectedInvoiceId]\n const vendorInvoices = getVendorInvoices(state)\n\n const hasAnyValidationError = _.some(allocationSummary, 'hasValidationError')\n\n return {\n vendorCredit: getVendorCredit(state),\n vendorInvoices,\n showAllInvoices: getShowAllInvoices(state),\n mode: getMode(state),\n selectedInvoiceAllocationSummary,\n canSubmit: canSubmit(state),\n selectedInvoice: getSelectedInvoice(state),\n hasAnyValidationError\n }\n}\n\nconst mapDispatchToProps = (dispatch, ownProps) => {\n return {\n onSetShowAllInvoices: (value) => { dispatch(appActions.setShowAllInvoices(value))},\n onSetMode: (mode) => { dispatch(appActions.setMode(mode))},\n onSave: () => { dispatch(submitVendorCredit())},\n onSelectInvoice: (invoiceId) => { dispatch(selectInvoice(invoiceId))},\n }\n}\n\nApp = connect(\n mapStateToProps,\n mapDispatchToProps\n)(App)\n\nexport default App\n\n\n\n\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\n\nconst {\n setShowAllInvoices,\n setMode,\n setSelectedInvoice,\n setCreditBalanceCents\n} = actions\n\nconst reducer = createReducer({\n [setShowAllInvoices]: (app, showAllInvoices ) => {\n return { ...app, showAllInvoices, selectedInvoiceId: null }\n },\n [setMode]: (app, mode) => {\n return dotProp.set(app, 'mode', mode)\n },\n [setSelectedInvoice]: (app, invoiceId) => {\n return dotProp.set(app, 'selectedInvoiceId', invoiceId)\n },\n [setCreditBalanceCents]: (app, grossCreditBalanceCents) => {\n return dotProp.set(app, 'grossCreditBalanceCents', grossCreditBalanceCents)\n },\n},\n{\n})\n\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as appActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\n\nconst d = dotProp\nconst {\n disputesLoaded,\n} = actions\n\nconst reducer = createReducer({\n [disputesLoaded]: (api, {vendorInvoiceId} ) => {\n return d.set(api, 'loadedDisputeInvoiceIds.$end', vendorInvoiceId)\n },\n},\n{})\n\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as apiActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\n\nconst {\n} = actions\n\nconst reducer = createReducer({\n //[setGrossCreditBalanceCents]: (vendorCredit, grossCreditBalanceCents) => {\n //return dotProp.set(vendorCredit, 'grossCreditBalanceCents', grossCreditBalanceCents)\n //},\n},\n{})\n\n\nexport default reducer\n\n","import { createAction } from 'redux-act';\n\n//const setGrossCreditBalanceCents = createAction(\"set current gross balance total cents\");\n\nexport default {\n //setGrossCreditBalanceCents,\n}\n\n","import reducer from './reducer'\n\nexport { default as vendorCreditActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\n\nconst d = dotProp\n\nconst {\n setVendorCreditId,\n loadSuccess\n} = actions\n\nconst reducer = createReducer({\n [setVendorCreditId]: (disputeLedgerItems, { ids, vendorCreditId } ) => {\n return _.reduce(_.flatten([ids]), (result, id) => {\n return dotProp.merge(result, `byId.${id}`, { vendorCreditId })\n }, disputeLedgerItems)\n },\n [loadSuccess]: (disputeLedgerItems, { loadedDisputeLedgerItems } ) => {\n return _.reduce(loadedDisputeLedgerItems, (result, disputeLedgerItem) => {\n return d.set(result, `byId.${disputeLedgerItem.id}`, disputeLedgerItem)\n }, disputeLedgerItems)\n },\n\n\n},\n{})\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as disputeLedgerItemsActions } from \"./actions\";\n\nexport default reducer\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\nimport { getTempId } from 'sharedUtils'\nvar d = dotProp\n\nconst {\n updateCreditAllocation,\n markForDestroy,\n updateFromServer\n} = actions\n\nconst reducer = createReducer({\n [updateCreditAllocation]: (vendorCreditAllocations, { vendorInvoiceId, vendorCreditId, args } ) => {\n const { id = getTempId() } = (_.find(vendorCreditAllocations.byId, { vendorInvoiceId, vendorCreditId }) || {})\n\n var newArgs = { ...args }\n\n if(_.has(newArgs, 'grossTotal')) {\n var grossTotalFloat = parseFloat(newArgs.grossTotal)\n newArgs.grossTotalCents = isNaN(grossTotalFloat) ? 0 : Math.round(grossTotalFloat * 100)\n }\n\n return dotProp.merge(vendorCreditAllocations, `byId.${id}`, { ...newArgs, id, vendorCreditId, vendorInvoiceId })\n },\n [updateFromServer]: (vendorCreditAllocations, allocationsFromServer ) => {\n return _.reduce(allocationsFromServer, (result, allocation) => {\n return d.set(result, `byId.${allocation.id}`, allocation)\n }, vendorCreditAllocations)\n },\n [markForDestroy]: (vendorCreditAllocations, { id } ) => {\n return dotProp.merge(vendorCreditAllocations, `byId.${id}`, { '_destroy': '1' } )\n },\n},\n{})\n\nexport default reducer\n\n\n","import reducer from './reducer'\n\nexport { default as vendorCreditAllocationsActions } from \"./actions\";\n\nexport default reducer\n","import { createReducer } from 'redux-act';\nimport dotProp from 'dot-prop-immutable'\nimport appReducer from './app'\nimport apiReducer from './api'\nimport vendorCreditReducer from './vendorCredit'\nimport disputeLedgerItemsReducer from './disputeLedgerItems'\nimport vendorCreditAllocationsReducer from './vendorCreditAllocations'\n\nconst rootReducer = (state = {}, action) => {\n\n return {\n ...state,\n app: appReducer(state.app, action),\n api: apiReducer(state.api, action),\n vendorCredit: vendorCreditReducer(state.vendorCredit, action),\n disputeLedgerItems: disputeLedgerItemsReducer(state.disputeLedgerItems, action),\n vendorCreditAllocations: vendorCreditAllocationsReducer(state.vendorCreditAllocations, action)\n }\n\n}\n\nexport default rootReducer\n\n","import React from \"react\"\nimport { Provider } from 'react-redux';\nimport { RootNode, configureStore } from '../apps/allocate-credit'\n\nexport default (props) => {\n return (\n \n \n \n );\n}\n\n","import { createStore, applyMiddleware } from 'redux';\nimport rootReducer from './reducer'\nimport thunk from 'redux-thunk'\nimport { composeWithDevTools } from 'redux-devtools-extension';\n\nexport default function configureStore(initialState) {\n\n const store = createStore(rootReducer,\n initialState,\n composeWithDevTools(applyMiddleware(thunk)));\n\n if (module.hot) {\n module.hot.accept('./reducer', () => {\n const nextRootReducer = require('./reducer').default;\n store.replaceReducer(nextRootReducer);\n });\n }\n\n return store;\n\n}\n","import { createAction } from 'redux-act';\n\nconst setSubmitting = createAction(\"I set the form submitting bool\")\nconst updateForm = createAction(\"I set the form data\")\nconst formLoaded = createAction(\"form is loaded\")\nconst clearForm = createAction(\"I cleared the form\")\n\n\nexport default {\n setSubmitting,\n updateForm,\n formLoaded,\n clearForm\n}\n\n","import { createAction } from \"redux-act\";\n\nconst reloadServices = createAction(\"Reload Services\");\n\nexport default {\n reloadServices,\n};\n","import { createAction } from \"redux-act\";\n\nconst loadServiceTimeline = createAction(\"TIMELINE_LOAD_START\");\nconst loadServiceTimelineSuccess = createAction(\"TIMELINE_LOAD_SUCCESS\");\nconst loadServiceTimelineError = createAction(\"TIMELINE_LOAD_ERROR\");\n\nexport default {\n loadServiceTimeline,\n loadServiceTimelineSuccess,\n loadServiceTimelineError,\n};\n","import _ from 'lodashExtended'\n\nconst getCurrentForm = (state) => state.app.currentForm\n\n\nexport {\n getCurrentForm\n}\n","import actions from \"./actions\";\nimport serviceActions from \"../services/actions\";\nimport serviceTimelineActions from \"../serviceTimeline/actions\";\nimport { push } from \"redux-first-history\";\nimport { getCurrentForm } from \"./selectors\";\nimport { prepareSubmitData } from \"sharedUtils\";\n\nconst selectMonth = (monthId) => (dispatch, getState) => {\n const state = getState();\n\n const currentForm = getCurrentForm(state);\n\n if (_.isPresent(_.get(currentForm, \"form.transitionOn\"))) {\n monthId = parseInt(monthId);\n const year = Math.floor(monthId / 12) + 1970;\n const month = (monthId % 12) + 1;\n\n const date = new Date(`${year}-${month}-01`).toISOString().split(\"T\")[0];\n\n dispatch(actions.updateForm({ transitionOn: date }));\n }\n\n dispatch(push(`/month/${monthId}`));\n};\n\nconst loadForm = (name, url) => (dispatch, getState) => {\n fetch(url, {\n credentials: \"same-origin\",\n headers: {\n Accept: \"application/json\",\n },\n })\n .then((res) => res.json())\n .then((data) => {\n dispatch(actions.formLoaded({ ...data, name, url }));\n })\n .catch((e) => {\n alert(e);\n });\n};\n\nconst submitForm = () => async (dispatch, getState) => {\n const currentForm = getCurrentForm(getState());\n const { form, url } = currentForm;\n const attributeKeyNames = [];\n\n dispatch(actions.setSubmitting(true));\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n credentials: \"same-origin\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(\n prepareSubmitData(\n { service_mapping: _.omit(form, [\"submitting\"]) },\n attributeKeyNames,\n ),\n ),\n });\n const data = await response.json();\n\n dispatch(actions.setSubmitting(false));\n\n if (response.status === 422) {\n dispatch(actions.formLoaded(data));\n } else if (response.status === 201) {\n dispatch(refreshData());\n dispatch(actions.clearForm());\n } else {\n console.error(\"Unexpected response:\", response);\n }\n } catch (error) {\n console.error(\"Error submitting the form:\", error);\n dispatch(actions.setSubmitting(false));\n }\n};\n\nconst refreshData = () => async (dispatch, getState) => {\n const { serviceMappingPath: url } = getState();\n try {\n dispatch(serviceTimelineActions.loadServiceTimeline());\n\n const response = await fetch(url, {\n method: \"GET\",\n credentials: \"same-origin\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (response) {\n const data = await response.json();\n dispatch(serviceTimelineActions.loadServiceTimelineSuccess(data));\n dispatch(serviceActions.reloadServices(data));\n } else {\n throw new Error(\"Failed to fetch data\");\n }\n } catch (error) {\n dispatch(serviceTimelineActions.loadServiceTimelineError(error));\n }\n};\n\nexport { selectMonth, loadForm, submitForm, refreshData };\n","import React, { useEffect, useMemo, useRef } from 'react'\nimport PropTypes from 'prop-types'\nimport classNames from 'classnames'\nimport createGuid from 'createGuid'\nimport ReactTooltip from 'react-tooltip'\nimport { Link } from 'sharedComponents'\nimport { faQuestionCircle } from '@fortawesome/free-regular-svg-icons'\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\nimport { averageHex, colorShade } from '../utils'\nimport { chain, isEmpty, map } from 'lodash'\nimport { BillingDot, BillingDotHole, BillingInfo } from './BillingInfo'\n\nfunction isTerminationMonth (terminationDate, currentMonth) {\n const termination = new Date(terminationDate)\n return (\n termination.getFullYear() === currentMonth.year &&\n termination.getMonth() === new Date(currentMonth.name + ' 1').getMonth()\n )\n}\n\nconst unexpectedAccountColor = '#D8D8D8'\n\nconst baseStyles = ({ isTerminatedThisMonth }) => ({\n height: '50px',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n position: 'relative',\n borderBottom: '1px solid #AAB2BD',\n borderLeft: isTerminatedThisMonth\n ? '1px dashed rgba(252, 90, 90, 1)'\n : ''\n})\n\nconst ServiceTimeline = ({\n serviceTimeline,\n onSelectMonth,\n selectMonthId,\n services,\n ...rest\n}) => {\n const legendColor = useMemo(\n () => averageHex(map(services, 'color')),\n [services]\n )\n const { vendorAccounts, months } = serviceTimeline\n\n const legendItems = [\n {\n text: 'No Billing In Desired Account',\n color: 'transparent',\n background: legendColor,\n isDotHole: true\n },\n {\n text: 'Vendor billed Location in Desired Account',\n color: colorShade(legendColor, -70),\n background: legendColor\n },\n {\n text: 'Vendor did not bill location but did bill into Desired account',\n color: colorShade(legendColor, -70),\n background: legendColor,\n isDotHole: true\n },\n {\n text: 'Vendor billed Location in an unexpected account',\n color: colorShade(unexpectedAccountColor, -70),\n background: unexpectedAccountColor\n },\n {\n text: 'Vendor did not bill location but it was not expected',\n color: 'transparent',\n background: unexpectedAccountColor,\n isDotHole: true\n }\n ]\n\n const flexContainer = {\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n width: '100%'\n }\n\n // Adjust scrollbar to show selected month\n const scrollContainerRef = useRef(null)\n\n useEffect(() => {\n const scrollingContainer = scrollContainerRef.current\n if (scrollingContainer) {\n const selectedElement = scrollingContainer.querySelector('.selected')\n if (selectedElement) {\n const position =\n selectedElement.offsetLeft -\n scrollingContainer.offsetWidth / 2 +\n selectedElement.offsetWidth / 2\n scrollingContainer.scrollLeft = position\n }\n }\n }, [])\n\n return (\n \n
\n
\n
\n Account Number\n
\n\n {map(vendorAccounts, ({ number, uuid, name, id }) => {\n const dataTooltipId = createGuid()\n return (\n
\n \n {name}\n \n \n {number}\n \n
\n )\n })}\n
\n
\n
\n {chain(months)\n .groupBy('year')\n .map((months, year) => {\n return (\n
\n
\n {year}\n
\n
\n {map(months, (month) => {\n const {\n vendorAccountServiceMappings,\n locationVendorAccountUuids\n } = month\n\n return (\n
onSelectMonth(month.id)}\n >\n
\n {month.name[0]}\n
\n {map(vendorAccounts, ({ uuid, closedMonth, closedOn }) => {\n const serviceUuids = vendorAccountServiceMappings[uuid]\n const color = isEmpty(serviceUuids)\n ? '#D8D8D8'\n : averageHex(map(serviceUuids, (serviceUuid) => services[serviceUuid].color))\n\n const isTerminatedThisMonth = serviceUuids?.length > 0 &&\n isTerminationMonth(services[serviceUuids[0]].terminationDate, month)\n\n const monthClosed = closedMonth && closedMonth === month.id\n const closedAccount = closedMonth && closedMonth <= month.id\n\n if (\n uuid === 'a82c891c-1238-463a-8d62-49f989ed532f'\n ) {\n debugger // eslint-disable-line no-debugger\n }\n return (\n
\n \n
\n )\n })}\n
\n )\n })}\n
\n
\n )\n })\n .reverse()\n .value()}\n
\n
\n
\n\n
\n
\n \n {legendItems.map((item) => (\n
\n \n {item.isDotHole\n ? (\n \n )\n : (\n \n )}\n \n
{item.text} \n \n ))}\n
\n \n
\n
\n
\n )\n}\n\nServiceTimeline.propTypes = {\n onSelectMonth: PropTypes.func.isRequired,\n selectMonthId: PropTypes.number.isRequired\n}\n\nexport default ServiceTimeline\n","import React, { useState, useEffect } from 'react'\nimport PropTypes from 'prop-types'\nimport _ from 'lodashExtended'\nimport classNames from 'classnames'\nimport ReactTooltip from 'react-tooltip'\nimport createGuid from 'createGuid'\nimport { useSortBy, useTable } from \"react-table\";\nimport { DropdownSelect } from 'sharedComponents'\nimport { Link } from 'sharedComponents';\n\n\nfunction useFetch(url, opts, defaultData = null, extraDep) {\n const [data, setData] = useState(defaultData);\n useEffect(() => {\n fetch(url, opts)\n .then((res) => res.json())\n .then((data) => {\n setData(data);\n })\n .catch((e) => {\n alert(e);\n });\n }, [url, extraDep]);\n return [data, setData];\n}\n\n\nconst useRowSpan = (instance) => {\n const { allColumns } = instance;\n let rowSpanHeaders = [];\n\n allColumns.forEach((column) => {\n const { id, enableRowSpan } = column;\n\n if (enableRowSpan) {\n rowSpanHeaders = [\n ...rowSpanHeaders,\n { id, topCellValue: null, topCellIndex: 0 }\n ];\n }\n\n Object.assign(instance, { rowSpanHeaders });\n });\n};\n\n\nconst ACCOUNT_HEADER = \"ACCOUNT\"\n\nvar MonthDetails = ({\n url,\n services,\n onSelectMonth\n}) => {\n\n //const [data, setData, loading, hasError] = useFetch(url, {\n const [data, setData] = useFetch(\n url,\n {\n credentials: \"same-origin\",\n headers: {\n Accept: \"application/json\",\n },\n },\n { lines: [], vendorAccounts: [], vendorAccountServiceMappings: {} },\n services\n );\n\n const columns = React.useMemo(() => {\n return [\n {\n Header: \"DATE\",\n cellClassName: 'billing-details-date',\n accessor: \"date\",\n enableRowSpan: true,\n Cell: ({ value }) => moment(value).format(\"dddd DD\")\n },\n {\n Header: ACCOUNT_HEADER,\n cellClassName: 'billing-details-account',\n //combine the date and uuid in order to avoid the rowspan on accounts across dates\n accessor: (row) => row.date + row.vendorAccountUuid,\n enableRowSpan: true,\n Cell: ({row }) => {\n var { vendorAccountUuid: uuid } = row.original\n if(_.isBlank(uuid)) { return null } else {\n const dataTooltipId = createGuid()\n const vendorAccount = _.find(data.vendorAccounts, {uuid})\n return(<>\n \n {vendorAccount.name}\n \n \n { vendorAccount.number }\n \n >)\n\n }\n }\n },\n {\n Header: \"INVOICE\",\n accessor: \"vendorInvoiceId\",\n cellClassName: 'billing-details-invoice',\n enableRowSpan: true,\n\n Cell: ({value, row}) => {\n if(_.isBlank(value)) { return null } else {\n var dataTooltipId = createGuid()\n return(<>\n \n {row.original.vendorInvoiceNumber}\n \n \n \n \n\n >)\n\n }\n }\n\n\n },\n {\n Header: \"VLC\",\n accessor: \"vendorLocationCode\",\n cellClassName: 'billing-details-vlc',\n enableRowSpan: true,\n Cell: ({value, row}) => _.isBlank(value) ? null : {value}\n },\n {\n Header: \"VENDOR DESCRIPTOR\",\n accessor: \"vendorLocationDescriptor\",\n cellClassName: 'billing-details-vl-descriptor',\n Cell: ({ value: vendorLocationDescriptor, row }) => _.isPresent(row.original.vendorInvoiceId) ? vendorLocationDescriptor || \"Not Specified\" : null\n },\n {\n Header: \"Data\",\n accessor: \"chargeData\",\n cellClassName: 'billing-details-vl-data',\n Cell: ({ value: chargeData }) => {\n\n if(_.isBlank(chargeData)) { return null } else {\n var dataTooltipId = createGuid()\n\n return(<>\n \n {_.map(chargeData, (data, i) => {data}
)}\n \n \n >)\n\n }\n }\n }\n ];\n }, [data]);\n\n const {\n getTableProps,\n getTableBodyProps,\n headerGroups,\n rows,\n prepareRow,\n rowSpanHeaders\n } = useTable(\n { columns, data: data.lines },\n (hooks) => hooks.useInstance.push(useRowSpan),\n useSortBy\n );\n\n const getRowProps = (row) => {\n return {\n className: classNames(\"billing-month-details-date-row\", _.isBlank(row.original.chargeData) ? 'blank' : 'present' )\n }\n }\n\n const getCellProps = (cell) => {\n var style = {}\n if (cell.column.Header == ACCOUNT_HEADER) {\n const { date } = cell.row.original\n\n const { vendorAccountServiceMappings = {} } = data\n const serviceId = _.get(vendorAccountServiceMappings, `${date}.${cell.row.original.vendorAccountUuid}`)\n\n if(_.isPresent(serviceId)) {\n //if(_.isPresent(vendorAccountServiceMappings)) { debugger }\n style['borderLeft'] = `9px solid ${services[serviceId].color}`\n }\n\n }\n return {\n style: style,\n className: classNames(cell.column.cellClassName, {'multi-entry': cell.rowSpan > 1})\n }\n }\n\n if(_.isBlank(data.lines)) {\n return(Loading...
)\n } else {\n\n let {\n month,\n vendorAccounts,\n dates\n } = data\n\n console.log(data)\n\n return (\n \n
\n onSelectMonth(month.lastMonth.id)}\n style={{ cursor: \"pointer\" }}\n />{\" \"}\n \n {month.monthName} \n onSelectMonth(month.nextMonth.id)}\n style={{ cursor: \"pointer\" }}\n />{\" \"}\n \n {\n return { value: id, label: year };\n })}\n />\n
\n
\n \n {headerGroups.map((headerGroup) => (\n \n {headerGroup.headers.map((column) => (\n \n {column.render(\"Header\")}\n \n ))}\n \n ))}\n \n \n {rows.map((row, i) => {\n prepareRow(row);\n\n for (let j = 0; j < row.allCells.length; j++) {\n let cell = row.allCells[j];\n let rowSpanHeader = rowSpanHeaders.find(\n (x) => x.id === cell.column.id\n );\n\n if (rowSpanHeader) {\n if (\n rowSpanHeader.topCellValue === null ||\n rowSpanHeader.topCellValue !== cell.value\n ) {\n cell.isRowSpanned = false;\n rowSpanHeader.topCellValue = cell.value;\n rowSpanHeader.topCellIndex = i;\n cell.rowSpan = 1;\n } else {\n rows[rowSpanHeader.topCellIndex].allCells[j].rowSpan++;\n cell.isRowSpanned = true;\n }\n }\n }\n return null;\n })}\n\n {rows.map((row) => {\n return (\n \n {row.cells.map((cell) => {\n if (cell.isRowSpanned) return null;\n else\n return (\n \n {cell.render(\"Cell\")}\n \n );\n })}\n \n );\n })}\n \n
\n
\n );\n }\n\n\n\n\n}\n\n\nMonthDetails.propTypes = {\n url: PropTypes.string.isRequired,\n onSelectMonth: PropTypes.func.isRequired,\n}\n\n\nexport default MonthDetails\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport { IconButton, Tooltip, Typography } from \"@mui/material\";\nimport { includes } from \"lodash\";\nimport {\n FilterCenterFocus as SetIcon,\n Undo as ResetIcon,\n East as TransitionIcon,\n} from \"@mui/icons-material\";\n\nconst ICON_MAPPING = {\n setAccount: SetIcon,\n resetAccount: ResetIcon,\n transitionAccount: TransitionIcon,\n};\n\nconst ActionMenu = ({\n actions,\n monthId,\n selectedAction = {},\n onSelectAction,\n}) => {\n return (\n <>\n {Object.entries(actions).map(([name, basicUrl]) => {\n const parsedUrl = new URL(basicUrl);\n const urlParams = new URLSearchParams(parsedUrl.search);\n urlParams.set(\"month_id\", monthId);\n parsedUrl.search = urlParams.toString();\n const url = parsedUrl.toString();\n const active = includes(selectedAction.url, parsedUrl.pathname);\n const IconComponent = ICON_MAPPING[name];\n\n return (\n {formatName(name)}}\n placement=\"top\"\n arrow\n >\n onSelectAction(name, url)}>\n \n \n \n );\n })}\n >\n );\n};\n\nconst formatName = (name) => {\n const words = name\n .split(/(?=[A-Z])/)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1));\n return words.join(\" \");\n};\n\nActionMenu.propTypes = {\n selectedAction: PropTypes.shape({\n url: PropTypes.string,\n name: PropTypes.string,\n }),\n onSelectAction: PropTypes.func.isRequired,\n};\n\nexport default ActionMenu;\n","import React, { useEffect } from \"react\";\nimport { useTable } from \"react-table\";\n\nconst TableForGroup = ({ groupOptions, columns, onRowSelect }) => {\n const [selectedRow, setSelectedRow] = React.useState(null);\n\n const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =\n useTable({ columns, data: groupOptions });\n\n useEffect(() => {\n if (selectedRow) {\n onRowSelect(selectedRow);\n }\n }, [selectedRow]);\n\n return (\n \n \n {headerGroups.map((headerGroup) => (\n \n {headerGroup.headers.map((column) => (\n \n {column.render(\"Header\")}\n \n ))}\n \n ))}\n \n \n {rows.map((row) => {\n prepareRow(row);\n return (\n setSelectedRow(row.original)}\n className={`hoverable-row ${\n row.original.uuid === selectedRow?.uuid ? \"selected\" : \"\"\n }`}\n style={{\n cursor: \"pointer\",\n color: \"#555656\",\n fontWeight: \"bolder\",\n }}\n >\n {row.cells.map((cell) => (\n {cell.render(\"Cell\")} \n ))}\n \n );\n })}\n \n
\n );\n};\n\nexport default TableForGroup;\n","import { flow, groupBy, intersection, map, orderBy } from 'lodash'\n\nconst GROUP_LABEL_ORDER = ['Same Commissioner', 'Other Comissioners']\n\nexport const getVendorAccountOptions = (vendorAccounts, location, service) => {\n let options\n\n if (location.nhsCommissionerAuthorityId && service.isNhsCommissioned) {\n const processOptions = flow(\n // 1. Group by authorityId condition\n vendorAccounts =>\n groupBy(vendorAccounts, vendorAccount => {\n const matchAuthority =\n vendorAccount.authorityId === location.nhsCommissionerAuthorityId\n return matchAuthority ? GROUP_LABEL_ORDER[0] : GROUP_LABEL_ORDER[1]\n }),\n\n // 2. Transform each group\n groupedAccounts =>\n map(groupedAccounts, (vendorAccounts, groupLabel) => {\n const initialOrder = orderBy(vendorAccounts, [\n 'premTypeNames',\n 'vendorAccountNumber'\n ])\n\n const sortCurrentVendorAccount = orderBy(initialOrder, [\n option =>\n option.vendorAccountNumber ===\n service.vendorAccount.vendorAccountNumber\n ? -1\n : 1\n ])\n\n const sortedOptions = orderBy(sortCurrentVendorAccount, [\n option => {\n const matchPremTypeNames = intersection(\n option.premTypeNames,\n service.vendorAccount.premTypeNames\n )\n return matchPremTypeNames.length === 0 ? 1 : 0\n }\n ])\n\n const noFilter = service?.actions?.setAccount\n const filteredOptions = noFilter\n ? sortedOptions\n : sortedOptions.filter(\n option =>\n option.vendorAccountNumber !==\n service.vendorAccount.vendorAccountNumber\n )\n\n return {\n label: groupLabel,\n options: filteredOptions\n }\n }),\n\n // 3. Order by label\n transformedGroups =>\n orderBy(transformedGroups, [\n ({ label }) => (GROUP_LABEL_ORDER[0] === label ? 0 : 1)\n ])\n )\n\n options = processOptions(vendorAccounts)\n } else {\n options = [\n {\n label: '', // empty label for non-grouped options\n options: vendorAccounts\n }\n ]\n }\n console.log(options)\n return options\n}","import _ from \"lodashExtended\";\nimport PropTypes from \"prop-types\";\nimport React, { useState } from \"react\";\nimport { Link } from \"sharedComponents\";\nimport TableForGroup from \"../TableForGroup\"; // Import the TableForGroup\nimport Button from \"@mui/material/Button\";\nimport { Divider, Typography } from \"@mui/material\";\nimport { getVendorAccountOptions } from \"../../app/utils\";\nimport VisibilityIcon from \"@mui/icons-material/Visibility\";\n\nconst TransitionAccount = ({\n currentForm,\n onChange,\n onSubmit,\n onClose,\n disabled,\n}) => {\n const { vendorAccounts, service, location } = currentForm?.context;\n const isSet = service?.actions?.setAccount;\n const options = getVendorAccountOptions(vendorAccounts, location, service);\n\n const [selectedRow, setSelectedRow] = useState(null);\n\n const columns = React.useMemo(\n () => [\n {\n Header: \"ACCOUNT #\",\n accessor: \"vendorAccountNumber\", // accessor is the \"key\" in the data\n },\n {\n Header: \"PREM TYPE\",\n accessor: (option) => option?.premTypeNames?.join(\" \") || \"\",\n },\n {\n Header: \"DESCRIPTOR\",\n accessor: \"authorityName\",\n },\n {\n Header: \"LAST BILLED\",\n accessor: \"lastBilledOn\",\n Cell: ({ value, row }) => {\n const { closedMonthName } = row.original;\n return _.isPresent(closedMonthName)\n ? `Closed ${closedMonthName}`\n : value;\n },\n },\n {\n Header: \"View\",\n accessor: \"id\",\n Cell: ({ value }) => {\n return (\n \n \n \n );\n },\n },\n ],\n [],\n );\n\n const rowSelectHandler = (row) => {\n setSelectedRow(row);\n onChange({ vendorAccountUuid: row.uuid });\n };\n\n return (\n <>\n \n {options.map((group) => (\n
\n {group.label === \"Other Comissioners\" && (\n \n \n {group.label}\n \n \n )}\n\n \n \n ))}\n
\n \n \n Cancel\n \n \n {isSet ? \"Set\" : \"Transition\"}\n {selectedRow &&\n ` to ${selectedRow.authorityName}-${selectedRow.vendorAccountNumber}`}\n \n
\n >\n );\n};\n\nTransitionAccount.propTypes = {\n currentForm: PropTypes.object.isRequired,\n onClose: PropTypes.func.isRequired,\n onChange: PropTypes.func.isRequired,\n onSubmit: PropTypes.func.isRequired,\n};\n\nexport default TransitionAccount;\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport Select from \"react-select\";\nimport { getVendorAccountOptions } from \"../../app/utils\";\nimport { Button, Divider, Typography } from \"@mui/material\";\n\nconst SetAccount = ({ currentForm, onChange, onClose, onSubmit }) => {\n const { vendorAccounts, service, location } = currentForm?.context;\n\n var options = getVendorAccountOptions(vendorAccounts, location, service);\n\n return (\n \n
\n \n Set Account\n \n \n
onChange({ vendorAccountUuid: value })}\n />\n \n \n Cancel\n \n \n Set Account\n \n
\n \n );\n};\n\nSetAccount.propTypes = {\n currentForm: PropTypes.object.isRequired,\n onClose: PropTypes.func.isRequired,\n onChange: PropTypes.func.isRequired,\n onSubmit: PropTypes.func.isRequired,\n};\n\nexport default SetAccount;\n","import React, { useState } from \"react\";\nimport PropTypes from \"prop-types\";\nimport { last } from \"lodash\";\nimport { StyledDialog } from \"sharedComponents\";\nimport DialogContent from \"@mui/material/DialogContent\";\nimport IconButton from \"@mui/material/IconButton\";\nimport Button from \"@mui/material/Button\";\nimport Typography from \"@mui/material/Typography\";\n\nvar ResetAccount = ({ currentForm, onChange, onClose, onSubmit }) => {\n const { previousStates } = currentForm?.context;\n const [open, setOpen] = useState(false);\n const [startOver, setStartOver] = useState(false);\n\n const lastEvent = last(previousStates);\n console.log(lastEvent, previousStates);\n\n const displayText = startOver ? \"Start Over\" : \"Undo\";\n\n const handleCloseModal = () => setOpen(false);\n\n const handleStartOver = () => {\n setOpen(true);\n setStartOver(true);\n };\n\n const submitStartOver = () => {\n onChange({ resetToEventId: null });\n onSubmit();\n };\n\n const submitUndo = () => {\n onChange({ resetToEventId: lastEvent.eventId });\n onSubmit();\n };\n\n return (\n <>\n \n \n Cancel\n \n\n \n Start Over\n \n\n {lastEvent?.eventId && (\n setOpen(true)}\n >\n Undo\n \n )}\n
\n\n \n \n theme.palette.grey[500],\n }}\n >\n \n \n theme.palette.common.white,\n }}\n >\n {`Are you sure you want to ${displayText}`}\n \n \n \n Cancel\n \n \n {`Yes, ${displayText}`}\n \n
\n \n \n >\n );\n};\n\nResetAccount.propTypes = {\n currentForm: PropTypes.object.isRequired,\n onClose: PropTypes.func.isRequired,\n onChange: PropTypes.func.isRequired,\n onSubmit: PropTypes.func.isRequired,\n};\n\nexport default ResetAccount;\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport getType from \"./forms\";\nimport TransitionAccount from \"./forms/TransitionAccount\";\nimport SetAccount from \"./forms/SetAccount\";\nimport ResetAccount from \"./forms/ResetAccount\";\n\nconst FORM_MAPPING = {\n TransitionAccount: TransitionAccount,\n SetAccount: TransitionAccount,\n ResetAccount: ResetAccount,\n};\n\nconst Form = ({ currentForm, onClose, onChange, onSubmit }) => {\n const { type, form } = currentForm;\n const FormType = FORM_MAPPING[type];\n\n if (!currentForm) return;\n\n if (!FormType) {\n throw (\n 'missing form component for \"' +\n type +\n '\", perhaps you forgot to add it to forms/index.js?'\n );\n }\n\n const disabled = form?.submitting;\n\n return (\n \n );\n};\n\nForm.propTypes = {\n currentForm: PropTypes.object.isRequired,\n onClose: PropTypes.func.isRequired,\n onChange: PropTypes.func.isRequired,\n onSubmit: PropTypes.func.isRequired,\n};\n\nexport default Form;\n","import React from 'react'\nimport ActionMenu from './ActionMenu'\nimport Form from './Form'\nimport { useTable } from 'react-table'\nimport { Divider, Typography } from '@mui/material'\nimport KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'\n\nfunction formatDate (input, day = true) {\n const parts = input.split('-')\n const date = new Date(parts[0], parts[1] - 1, parts[2]) // parsed in local timezone\n const month = date.toLocaleString('en', { month: 'short' })\n const year = date.getFullYear()\n\n if (!day) return `${month} ${year}`\n\n return `${date.getDate()} ${month} ${year}`\n}\n\nconst errorStyles = {\n backgroundColor: '#f8d7da',\n color: '#721c24',\n padding: '8px 12px',\n margin: '8px 0',\n borderRadius: '4px',\n border: '1px solid #f5c6cb'\n}\n\nconst ServiceBox = ({\n service,\n monthId,\n onSelectAction,\n currentForm,\n isDeveloper,\n onClearForm,\n onFormChange,\n onSubmitForm\n}) => {\n const {\n vendorAccount: { vendorLocationAccounts }\n } = service\n\n const columns = React.useMemo(\n () => [\n {\n Header: 'VLC',\n accessor: 'vendorLocationCode'\n },\n {\n Header: 'First Billed',\n accessor: 'firstBilledOn'\n },\n {\n Header: 'Last Billed',\n accessor: 'lastBilledOn'\n }\n ],\n []\n )\n\n const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =\n useTable({ columns, data: vendorLocationAccounts })\n\n const showForm = currentForm?.context?.service?.uuid === service?.uuid\n\n if (!service) return <>Loading>\n\n return (\n \n
\n
\n \n \n
\n {service.title}\n \n\n {service.terminationDate && (\n
\n {moment(service.terminationDate) < moment() ? 'Terminated' : 'Terminating' } on {formatDate(service.terminationDate)}\n \n )}\n
\n {service.commissionerStatus === 'ods_not_set'\n ? (\n
\n ODS Authority Not Set \n
\n )\n : null}\n {service.commissionerStatus === 'wrong_commissioner'\n ? (\n
\n Wrong Commissioner \n
\n )\n : null}\n
\n
\n {service.vendorAccount.name} {service.vendorAccount.number}\n
\n {service?.vendorAccount?.closedOn && (\n
\n Account Closed from {service.vendorAccount.closedOn}\n \n )}\n
\n
{service.vendorAccount.number}
\n
\n Visits Frequency{' '}\n {service?.visitPlanName || 'Unknown' }\n
\n {vendorLocationAccounts?.length > 0 && (\n
\n \n {headerGroups.map((headerGroup, i) => (\n \n {headerGroup.headers.map((column, iTh) => (\n \n {column.render('Header')}\n \n ))}\n \n ))}\n \n \n {rows.map((row, i) => {\n prepareRow(row)\n return (\n \n {row.cells.map((cell, iTd) => (\n {cell.render('Cell')} \n ))}\n \n )\n })}\n \n
\n )}\n\n {showForm && currentForm?.errors && currentForm?.errors.length > 0 && (\n
\n {currentForm.errors.map((error, index) => (\n
\n {error}\n
\n ))}\n
\n )}\n\n
{isDeveloper ? `Service Id: ${service.id}` : null}
\n\n
\n {currentForm?.form?.transitionOn && showForm && (\n
\n \n Transition From {formatDate(currentForm.form.transitionOn, false)}\n \n To Account\n \n \n )}\n\n {showForm && currentForm?.type === 'SetAccount' && (\n
\n \n Set Account\n \n \n )}\n\n {currentForm && showForm && (\n
\n )}\n
\n
\n )\n}\n\nexport default ServiceBox\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport { connect } from \"react-redux\";\nimport _ from \"lodashExtended\";\nimport { loadForm, selectMonth, submitForm } from \"../app/operations\";\nimport { getCurrentForm } from \"../app/selectors\";\n\nimport ServiceTimeline from \"./ServiceTimeline\";\nimport MonthDetails from \"./MonthDetails\";\nimport ServiceBox from \"./ServiceBox\";\nimport appActions from \"../app/actions\";\nimport { Redirect, Route, Switch } from \"react-router-dom\";\n\n\nvar App = (props) => {\n let {\n services,\n initialMonthId,\n billingMonthDetailsBasePath,\n onSelectAction,\n onFormChange,\n onClearForm,\n onSubmitForm,\n currentForm,\n isDeveloper,\n serviceTimeline,\n } = props;\n\n return (\n \n {serviceTimeline.isLoading && (\n
\n )}\n
\n \n {\n const monthId = _.toInteger(match.params.monthId);\n\n return (\n <>\n \n
\n \n \n
\n
\n {_.map(services, (service) => (\n \n ))}\n
\n
\n >\n );\n }}\n />\n \n
\n );\n};\n\nApp.propTypes = {\n initialMonthId: PropTypes.number.isRequired,\n billingMonthDetailsBasePath: PropTypes.string.isRequired,\n};\n\nconst mapStateToProps = (state, props) => {\n return {\n ...state,\n currentForm: getCurrentForm(state),\n };\n};\n\nconst mapDispatchToProps = (dispatch, ownProps) => {\n return {\n onSelectMonth: (monthId) => dispatch(selectMonth(monthId)),\n onSelectAction: (name, url) => dispatch(loadForm(name, url)),\n onClearForm: () => dispatch(appActions.clearForm()),\n onFormChange: (newAttr) => dispatch(appActions.updateForm(newAttr)),\n onSubmitForm: () => dispatch(submitForm()),\n };\n};\n\nApp = connect(mapStateToProps, mapDispatchToProps)(App);\n\nexport default App;\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\n\n\nvar d = dotProp\nconst {\n setSubmitting,\n updateForm,\n formLoaded,\n clearForm\n} = actions\n\nconst reducer = createReducer({\n [setSubmitting]: (app, submitting ) => {\n return dotProp.merge(app, 'currentForm.form', { submitting } )\n },\n [clearForm]: (app) => {\n return d.delete(app, 'currentForm')\n },\n [formLoaded]: (app, form ) => {\n return d.merge(app, 'currentForm', form)\n },\n [updateForm]: (app, newAttr ) => {\n return d.merge(app, 'currentForm.form', newAttr)\n },\n},\n {} )\n\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as appActions } from \"./actions\";\n\nexport default reducer\n","import actions from \"./actions\";\nimport { createReducer } from \"redux-act\";\nimport dotProp from \"dot-prop-immutable\";\nimport _ from \"lodashExtended\";\n\nconst d = dotProp;\n\nconst {reloadServices } = actions;\n\nconst reducer = createReducer(\n {\n [reloadServices]: (_state, payload) => {\n return { ...payload.services };\n },\n },\n {}\n);\n\nexport default reducer;\n","import reducer from './reducer'\n\nexport { default as servicesActions } from \"./actions\";\n\nexport default reducer\n","import actions from \"./actions\";\nimport { createReducer } from \"redux-act\";\nimport dotProp from \"dot-prop-immutable\";\n\nconst d = dotProp;\n\nconst {\n loadServiceTimeline,\n loadServiceTimelineSuccess,\n loadServiceTimelineError,\n} = actions;\n\nconst reducer = createReducer(\n {\n [loadServiceTimeline]: (state) => {\n return d.set(state, \"isLoading\", true);\n },\n\n [loadServiceTimelineSuccess]: (_state, payload) => {\n return { ...payload.serviceTimeline, isLoading: false };\n },\n\n [loadServiceTimelineError]: (state, error) => {\n let newState = d.set(state, \"isLoading\", false);\n newState = d.set(newState, \"error\", error);\n return newState;\n },\n },\n {}\n);\n\nexport default reducer;\n","import reducer from \"./reducer\";\n\nexport { default as serviceTimelineActions } from \"./actions\";\n\nexport default reducer;\n","import { createReducer } from \"redux-act\";\nimport dotProp from \"dot-prop-immutable\";\nimport _ from \"lodashExtended\";\nimport appReducer from \"./app\";\nimport servicesReducer from \"./services\";\nimport serviceTimlelineReducer from \"./serviceTimeline\";\n\nconst createRootReducer = (routerReducer) => {\n const reducer = (state = {}, action) => {\n return {\n ...state,\n app: appReducer(state.app, action),\n services: servicesReducer(state.services, action),\n serviceTimeline: serviceTimlelineReducer(state.serviceTimeline, action),\n router: routerReducer(state.router, action),\n };\n };\n\n return reducer;\n};\n\nexport default createRootReducer;\n","import { createStore, applyMiddleware } from \"redux\";\nimport createRootReducer from \"./reducer\";\nimport thunk from \"redux-thunk\";\nimport { createReduxHistoryContext } from \"redux-first-history\";\nimport { composeWithDevTools } from \"redux-devtools-extension\";\nimport { createHashHistory } from \"history\";\n\nconst { createReduxHistory, routerMiddleware, routerReducer } =\n createReduxHistoryContext({\n history: createHashHistory(),\n });\n\nexport default function configureStore(initialState) {\n const rootReducer = createRootReducer(routerReducer);\n\n const store = createStore(\n rootReducer,\n initialState,\n composeWithDevTools(applyMiddleware(routerMiddleware, thunk)),\n );\n\n if (module.hot) {\n module.hot.accept(\"./reducer\", () => {\n const nextCreateRootReducer = require(\"./reducer\").default;\n store.replaceReducer(createRootReducer(routerReducer));\n });\n }\n\n const history = createReduxHistory(store);\n\n return { store, history };\n}\n\n//export const history = createReduxHistory(store);\n","import React from \"react\";\nimport { Provider } from \"react-redux\";\nimport { Router } from \"react-router-dom\";\n\nimport { RootNode, configureStore } from \"../apps/service-mappings\";\nimport { ThemeProvider } from \"@mui/material/styles\";\nimport { theme } from \"../theme\";\n\nexport default (props) => {\n const { store, history } = configureStore(props);\n\n return (\n \n \n \n \n \n \n \n );\n};\n","const addEventListener = (el, eventName, handler) => {\n if (el.addEventListener) {\n el.addEventListener(eventName, handler);\n } else {\n el.attachEvent(\"on\" + eventName, function () {\n handler.call(el);\n });\n }\n};\n\nexport const addEventListeners = (selector, type, handler) => {\n const elements = document.querySelectorAll(selector);\n for (let i = 0; i < elements.length; i++) {\n addEventListener(elements[i], type, handler);\n }\n};\n\nconst removeEventListener = (el, eventName, handler) => {\n if (el.removeEventListener) {\n el.removeEventListener(eventName, handler);\n } else {\n el.detachEvent(\"on\" + eventName, function () {\n handler.call(el);\n });\n }\n};\n\nexport const removeEventListeners = (selector, type, handler) => {\n const elements = document.querySelectorAll(selector);\n for (let i = 0; i < elements.length; i++) {\n removeEventListener(elements[i], type, handler);\n }\n};\n\n//export const debounce = (func, wait, immediate) => {\n //let timeout;\n\n //return function executedFunction() {\n //const context = this;\n //const args = arguments;\n\n //const later = function () {\n //timeout = null;\n //if (!immediate) func.apply(context, args);\n //};\n\n //const callNow = immediate && !timeout;\n\n //clearTimeout(timeout);\n\n //timeout = setTimeout(later, wait);\n\n //if (callNow) func.apply(context, args);\n //};\n//};\n","import dotProp from 'dot-prop-immutable';\n\nimport { COLLECTION_ID } from './ConfirmatoryStatementsPage';\n\nexport const selectConfirmatoryStatementsState = (state) => {\n return (\n dotProp.get(\n state.firestore,\n `data.${COLLECTION_ID}.${state.app?.currentUser?.id}`\n ) || {}\n ) as IConfirmatoryStatement\n};\n\nexport const checkAreConfirmatoryStatementsCompleted = (state) => {\n const confirmatoryStatementsState = selectConfirmatoryStatementsState(state);\n const {\n fullName,\n jobTitle,\n competenceEvidences,\n willPawaBeCompletedWithPhysicalPresence,\n hasKnowledgeOfHealthcareWaste,\n } = confirmatoryStatementsState;\n const result =\n !!fullName &&\n !!jobTitle &&\n (competenceEvidences?.length ?? 0) > 0 &&\n [\"yes\", \"no\"].includes(willPawaBeCompletedWithPhysicalPresence || '') &&\n [\"yes\", \"no\"].includes(hasKnowledgeOfHealthcareWaste || '');\n\n return result;\n};\n","import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { CheckboxInput, ModalBox, TextInput, YesNoInput } from 'auditComponents';\nimport { push } from 'connected-react-router';\nimport dotProp from 'dot-prop-immutable';\nimport _ from 'lodashExtended';\nimport * as React from 'react';\nimport { useReducer } from 'react';\nimport { connect } from 'react-redux';\nimport { useHistory, useRouteMatch } from 'react-router-dom';\nimport { ModalRoute } from 'react-router-modal';\nimport { Btn } from 'sharedComponents';\n\nimport { areAnySectionStarted } from '../sections';\nimport { updateConfirmatoryStatementsState } from './operations';\nimport { checkAreConfirmatoryStatementsCompleted, selectConfirmatoryStatementsState } from './selectors';\n\n// NOTE: not sure how to type this\nconst Checkbox = (CheckboxInput as any).Checkbox as typeof React.Component;\n\nexport const COLLECTION_ID = \"confirmatoryStatements\";\n\nconst d = dotProp;\n\nconst NoCompetenceModal = ({ onSubmit, closeModal }) => {\n return (\n {\n onSubmit();\n closeModal();\n }}\n className=\"location-update-modal\"\n >\n \n Since none of the Competence Evidence has been selected, please ask\n Anenta, or another qualified third-party auditor, to carry it out for\n you. Those audits come at a fee. Alternatively please ask your colleague\n that has the relevant working knowledge to conduct this audit.\n
\n \n );\n};\n\n// NOTE: haven't decided if we need this yet\nconst getIncompleteMessage = (data) => {\n const {\n willPawaBeCompletedWithPhysicalPresence,\n hasKnowledgeOfHealthcareWaste,\n fullName,\n jobTitle,\n competenceEvidences = [],\n } = data;\n\n const toCheck = [\n willPawaBeCompletedWithPhysicalPresence,\n hasKnowledgeOfHealthcareWaste,\n fullName,\n jobTitle,\n ];\n\n const blankFields = _.filter(toCheck, _.isBlank).length;\n\n return blankFields > 0\n ? `There ${\n blankFields == 1 ? \"is\" : \"are\"\n } ${blankFields} unanswered question${\n blankFields == 1 ? \"\" : \"s\"\n } remaining`\n : null;\n};\n\nconst FULL_COMPETENCE_EVIDENCES_QUESTIONS = {\n // TODO: add this back when we have `Waste Management Training` link\n // hasCompletedWasteManagementTraining: {\n // label: \"I completed the Waste Management training provided in this report\",\n // },\n isLongStandingClinicalPro: {\n label: \"I am a long-standing clinical professional\",\n },\n isLongStandingHealthcareMgmtPro: {\n label: \"I am a long-standing healthcare management professional\",\n },\n hasKnowledgeOfWasteMgmtPractices: {\n label:\n \"I have a working knowledge of waste management practices and guidance\",\n },\n isQualifiedAuditingPro: { label: \"I am a qualified auditing professional\" },\n hasRecentTrainingOnWasteMgmtPracticesAndRequirements: {\n label:\n \"I have had recent training on waste management practices and requirements\",\n },\n};\nconst YES_NO_QUESTIONS = {\n willPawaBeCompletedWithPhysicalPresence: {\n label:\n \"This pre-acceptance waste audit (PAWA) will be completed with a physical presence at the named premises using visual inspection and the assistance of an online tool.\",\n },\n hasKnowledgeOfHealthcareWaste: {\n label:\n \"Does the person undertaking the audit have a working knowledge of healthcare waste and its composition, classification, and packaging for road transport and an understanding of Waste Transfer Notes and Hazardous Waste Consignment Notes?\",\n },\n};\nconst ConfirmatoryStatementPageLayout = ({ children }) => {\n return (\n \n
\n
\n
Confirmatory Statements
\n\n
\n
\n
\n
\n
\n );\n};\n\nconst validateFields = (updatedAttrs) => {\n let errors = {};\n if (\"jobTitle\" in updatedAttrs) {\n errors[\"jobTitle\"] = !!updatedAttrs.jobTitle\n ? null\n : [\"Please enter a Job Title\"];\n }\n return errors;\n};\n\nexport const ConfirmatorySidenav = () => {\n return (\n \n
\n
\n \n Additional information to waste management is available at:\n \n
\n\n
\n
\n
\n );\n};\n\n\nconst ConfirmatoryStatementsPage = ({\n onChange,\n onNavigate,\n confirmatoryStatementsData,\n hadStartedPAA,\n hasCompletedConfirmatoryStatements\n}: ConfirmatoryStatementsPageProps) => {\n// }) => {\n // if (hasCompletedConfirmatoryStatements) return onNavigate(\"/\");\n\n const {\n willPawaBeCompletedWithPhysicalPresence,\n hasKnowledgeOfHealthcareWaste,\n fullName,\n jobTitle,\n competenceEvidences = [],\n } = confirmatoryStatementsData;\n\n const incompleteMessage = getIncompleteMessage(confirmatoryStatementsData);\n\n // NOTE: looks like we are probably not gonna be doing any validations\n const [errors, setErrors] = useReducer(\n (errorStates, updatedAttr) => ({\n ...errorStates,\n ...validateFields(updatedAttr),\n }),\n {}\n );\n\n const { url } = useRouteMatch();\n const history = useHistory();\n const noCompetenceModalPath = `${url}/noCompetence`;\n const gotoNoCompetenceModal = () => history.push(noCompetenceModalPath);\n const handleCheckCompetence = () => {\n const hasAnyCompetence = competenceEvidences.length > 0;\n if (!hasAnyCompetence) return gotoNoCompetenceModal();\n\n // push route to go back\n onNavigate(\"/\");\n };\n\n return (\n \n {/* used for testing typescript */}\n {/* */}\n\n {incompleteMessage ? (\n \n {\" \"}\n {incompleteMessage}\n
\n ) : null}\n\n {} }}\n component={NoCompetenceModal}\n className=\"an-modal-lg react-router-modal__modal\"\n />\n\n \n
\n
\n\n
\n\n {/* TODO: add this back when we have `Waste Management Training` link */}\n {false && hasKnowledgeOfHealthcareWaste === \"no\" && (\n
\n
\n
\n \n Please conduct the following Waste Management Training -{\" \"}\n link \n \n
\n
\n
\n )}\n\n
\n
\n \n
\n\n
\n
\n Anenta have worked in conjunction with HEE to develop a\n standardised training package that encompasses all areas of\n waste from NHS strategy to correct waste segregation. Use the\n link below to access e-learning for health and search Healthcare\n Waste Management and Disposal. If you do not have an account\n feel free to register for this free service.\n
\n\n
\n \n http://portal.e-lfh.org.uk/Component/Details/763177\n \n
\n
\n
\n\n
\n\n
\n\n
\n {Object.keys(FULL_COMPETENCE_EVIDENCES_QUESTIONS).map(\n (competenceKey, idx) => {\n const actualString =\n FULL_COMPETENCE_EVIDENCES_QUESTIONS[competenceKey].label;\n\n return (\n {\n // TODO: create a Set datastructure to refactor this.\n let result;\n if (bool) {\n if (!competenceEvidences.includes(actualString)) {\n result = [...competenceEvidences, actualString];\n }\n } else {\n result = competenceEvidences.filter(\n (value) => value !== actualString\n );\n }\n\n onChange(result, \"competenceEvidences\");\n }}\n />\n );\n }\n )}\n \n\n
\n \n {hadStartedPAA ? \"Continue with your audit\" : \"Start Your Audit\"}\n \n
\n
\n
\n \n );\n};\n\nconst mapStateToProps = (state) => {\n return {\n confirmatoryStatementsData: selectConfirmatoryStatementsState(state),\n hasCompletedConfirmatoryStatements:\n checkAreConfirmatoryStatementsCompleted(state),\n hadStartedPAA: areAnySectionStarted(state),\n };\n};\n\nconst mapDispatchToProps = (dispatch, {}) => {\n return {\n onChange: (value, name) => {\n dispatch(updateConfirmatoryStatementsState(d.set({}, name, value)));\n },\n onNavigate: (nextPath) => dispatch(push(nextPath)),\n };\n};\n\nconst ConnectedConfirmatoryStatementsPage = connect(\n mapStateToProps,\n mapDispatchToProps\n)(ConfirmatoryStatementsPage);\n\nexport default ConnectedConfirmatoryStatementsPage;\n","import { COLLECTION_ID } from \"./ConfirmatoryStatementsPage\";\n\nexport const updateConfirmatoryStatementsState = (args) => (dispatch, getState, { getFirebase, getFirestore }) => {\n const state = getState();\n const firestore = getFirestore();\n\n firestore\n .set(\n {\n collection: \"pre_acceptance_waste_audits\",\n doc: state.app.auditDocumentId,\n subcollections: [\n {\n collection: COLLECTION_ID,\n doc: state.app.currentUser.id.toString(),\n },\n ],\n },\n args,\n { merge: true }\n )\n .then(() => {\n dispatch({ type: \"UPDATE SUCCESS\" });\n })\n .catch((err) => {\n dispatch({ type: \"UPDATE ERROR\" }, err);\n });\n};\n","import PropTypes from 'prop-types';\nimport React from 'react';\nimport { Btn } from 'sharedComponents';\n\nvar SubmittedModal = ({ afterSubmitPath }) => {\n return (\n \n
\n
\n
\n
Thank you for submitting your Pre-Acceptance Waste Audit.
\n
\n A copy will be sent to your waste contractor and it will be available\n for you to access in Vector under 'Documents'\n
\n
\n
\n (window.location = afterSubmitPath)}\n className=\"w-phone-100 m-0\"\n styles=\"primary\"\n >\n Hit the Dashboard\n \n
\n
\n );\n};\n\nSubmittedModal.propTypes = {\n afterSubmitPath: PropTypes.string.isRequired,\n};\n\nexport default SubmittedModal;\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport _ from \"lodashExtended\";\nimport { Btn } from \"sharedComponents\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { faPaperPlane } from \"@fortawesome/free-solid-svg-icons\";\n\nvar SubmitWarningModal = ({\n onSubmit,\n closeModal\n}) => {\n return (\n \n
\n
\n
Are you sure you want to Submit the Audit?
\n
\n
\n
\n Before you submit this audit please ensure that you provide all required information\n and that all attachments are related to the question and are clearly visible.\n Missing information or unclear images may affect your audit score\n
\n
\n
\n \n Back to Overview\n \n \n Submit Audit\n \n
\n
\n );\n};\n\nexport default SubmitWarningModal;\n","import React, { useEffect } from 'react';\nimport PropTypes from \"prop-types\"\nimport { connect } from 'react-redux';\nimport _ from 'lodashExtended';\nimport { orderedSectionSummaryViews } from './sections'\nimport SubmittedModal from './SubmittedModal'\nimport SubmitWarningModal from './SubmitWarningModal'\n\nimport {\n SubmitSummary\n} from 'auditComponents'\n\n\nexport default (props) => {\n return \n}\n","import { StatusSummary } from 'auditComponents';\nimport { push } from 'connected-react-router';\nimport _ from 'lodashExtended';\nimport PropTypes from 'prop-types';\nimport React, { useEffect, useLayoutEffect, useState } from 'react';\nimport { isMobile } from 'react-device-detect';\nimport { connect } from 'react-redux';\nimport { firestoreConnect } from 'react-redux-firebase';\nimport { useMediaQuery } from 'react-responsive';\nimport { Redirect, Route, Switch, useLocation } from 'react-router-dom';\nimport StickyBox from 'react-sticky-box';\nimport { compose } from 'redux';\nimport { Link } from 'sharedComponents';\n\nimport { addEventListeners, removeEventListeners } from '../app/helper';\nimport { goToSummaryPage, submitAudit } from '../app/operations';\nimport { areAllSectionsComplete, getSectionStatusById } from '../sections/selectors';\nimport { getAuditDocument, selectRequiredBinGroupsForSectionId } from '../wasteAudit/selectors';\nimport ConfirmatoryStatementsPage, { ConfirmatorySidenav } from './ConfirmatoryStatements/ConfirmatoryStatementsPage';\nimport { checkAreConfirmatoryStatementsCompleted } from './ConfirmatoryStatements/selectors';\nimport sectionComponents, { orderedSectionIds } from './sections';\nimport SubmitSummary from './SubmitSummary';\nimport TestSection from './sections/TestSection';\n\nvar App = (props) => {\n const {\n allDataLoaded,\n wasteAudit,\n currentUser,\n hasCompletedConfirmatoryStatements,\n onNavigate,\n locationPath,\n } = props;\n\n const isMobileMode = useMediaQuery({ maxWidth: 992 });\n const location = useLocation();\n\n const [showSubmit, setShowSubmit] = useState(false);\n const [showSummaryBox, setShowSummaryBox] = useState(true);\n\n useEffect(() => {\n if (isMobile) {\n document.getElementById(\n \"dropdownMenuButtonNav\"\n ).innerHTML = ` `;\n }\n window.addEventListener(\"keyup\", function (event) {\n if (event.key === \"Enter\") {\n if (event.target.localName === \"textarea\") {\n return;\n }\n event.target.blur();\n }\n });\n\n return () => {\n window.removeEventListener(\"keyup\", () => {});\n };\n }, [isMobile]);\n\n const isBottom = (el) => {\n const height = window.innerHeight + 100;\n return el.getBoundingClientRect().bottom <= height;\n };\n\n const trackScrolling = _.debounce(\n () => {\n const wrappedElement = document.getElementById(\"main\");\n wrappedElement && isBottom(wrappedElement)\n ? setShowSubmit(true)\n : setShowSubmit(false);\n },\n 50,\n { maxWait: 200 }\n );\n\n useLayoutEffect(() => {\n if (isMobile) {\n addEventListeners(\"input\", \"focus\", (e) => {\n setShowSummaryBox(false);\n });\n\n addEventListeners(\"input\", \"blur\", (e) => {\n setShowSummaryBox(true);\n });\n\n return () => {\n removeEventListeners(\"input\", \"focus\");\n removeEventListeners(\"input\", \"blur\");\n };\n }\n }, [isMobile, wasteAudit]);\n\n useLayoutEffect(() => {\n if (isMobileMode) {\n setShowSummaryBox(location.pathname !== \"/submitSummary\");\n document.addEventListener(\"scroll\", trackScrolling);\n return () => {\n document.removeEventListener(\"scroll\", trackScrolling);\n };\n }\n }, [isMobileMode, wasteAudit]);\n\n const handleChangeConfirmatoryStatement = () => {\n onNavigate(\"/confirmatory-statement?mode=edit\");\n };\n\n // NOTE: use this to test typescript\n // return \n\n if (wasteAudit) {\n return (\n \n \n \n \n \n\n \n \n \n\n \n {!hasCompletedConfirmatoryStatements && (\n \n )}\n\n \n
\n
\n
\n
\n \n \n Pre Acceptance Waste Audit\n
\n
\n
\n
Change Confirmatory Statements
\n \n
\n\n
\n {_.map(sectionComponents, (Section, i) => (\n \n ))}\n \n
\n\n {!isMobileMode ? (\n
\n
\n \n \n \n\n \n \n
\n \n
\n ) : null}\n
\n
\n \n \n\n {isMobileMode && showSummaryBox ? (\n \n {/* TODO: revive this for the correct behavior in PAWA Need for Help */}\n {/* */}\n \n \n \n \n \n \n ) : null}\n \n );\n } else {\n return (\n \n );\n }\n};\n\nApp.propTypes = {\n auditDocumentId: PropTypes.string.isRequired,\n};\n\nconst mapStateToProps = (state, props) => {\n const { auditDocumentId, afterSubmitPath, currentUser, locationPath } =\n state.app;\n\n return {\n locationPath,\n auditDocumentId,\n wasteAudit: getAuditDocument(auditDocumentId, state),\n afterSubmitPath,\n currentUser,\n sectionStatusById: getSectionStatusById(state),\n allSectionsComplete: areAllSectionsComplete(state),\n hasCompletedConfirmatoryStatements:\n checkAreConfirmatoryStatementsCompleted(state),\n\n // For separate Summary View data\n binGroupSurveysForWasteProducedAndSegregation:\n selectRequiredBinGroupsForSectionId(\n \"waste_produced_and_segregation_at_this_premises\"\n )(state),\n binGroupSurveysForOtherWasteProduced: selectRequiredBinGroupsForSectionId(\n \"other_waste_produced_at_this_premises\"\n )(state),\n };\n};\n\nconst mapDispatchToProps = (dispatch, ownProps) => {\n return {\n onSubmitAudit: (successPath) => dispatch(submitAudit(successPath)),\n goToSummaryPage: () => dispatch(goToSummaryPage()),\n onNavigate: (nextPath) => dispatch(push(nextPath)),\n };\n};\n\nApp = compose(\n connect(mapStateToProps, mapDispatchToProps),\n firestoreConnect((initialProp) => {\n const { auditDocumentId } = initialProp;\n window.global = initialProp;\n\n return [\n {\n collection: \"pre_acceptance_waste_audits\",\n doc: auditDocumentId,\n },\n {\n collection: \"pre_acceptance_waste_audits\",\n doc: auditDocumentId,\n subcollections: [{ collection: \"sections\" }],\n storeAs: \"sections\", // make sure to include this\n },\n {\n collection: \"pre_acceptance_waste_audits\",\n doc: auditDocumentId,\n subcollections: [{ collection: \"wasteProductionAreas\" }],\n storeAs: \"wasteProductionAreas\", // make sure to include this\n },\n {\n collection: \"pre_acceptance_waste_audits\",\n doc: auditDocumentId,\n subcollections: [{ collection: \"binGroupSurveys\" }],\n storeAs: \"binGroupSurveys\",\n },\n {\n collection: \"pre_acceptance_waste_audits\",\n doc: auditDocumentId,\n subcollections: [{ collection: \"confirmatoryStatements\" }],\n storeAs: \"confirmatoryStatements\", // make sure to include this\n },\n ];\n })\n)(App);\n\nexport default App;\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\n\nconst {\n //setOnlineStatus,\n} = actions\n\nconst reducer = createReducer({\n //[setOnlineStatus]: (app, { payload }) => {\n //return dotProp.set(app, 'online', payload)\n //}\n},\n{ })\n\nreducer.options({\n payload: false\n});\n\n\nexport default reducer\n\n","import { createAction } from 'redux-act';\n\n//const updateRequest = createAction('update requested');\n//const updateSuccess = createAction('update success');\n//const setOnlineStatus = createAction('set online status')\n\nexport default {\n //updateRequest,\n //updateSuccess,\n //setOnlineStatus\n}\n\n","import reducer from './reducer'\n\nexport { default as appActions } from \"./actions\";\n\nexport default reducer\n","import { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\nimport { compose } from 'redux'\nimport { firestoreReducer } from 'redux-firestore';\n\nvar d = dotProp\n\nconst reducer = createReducer({\n ['@@reactReduxFirebase/FILE_UPLOAD_PROGRESS']: (firestore, action) => {\n return d.merge(\n firestore,\n `data.${_.replace(action.meta.options.storeProgressAt, /\\//g, '.')}`, \n { percentUploaded: action.payload.percent }\n )\n },\n ['@@reactReduxFirebase/FILE_UPLOAD_START']: (firestore, action) => {\n return d.merge(\n firestore,\n `data.${_.replace(action.payload.options.storeProgressAt, /\\//g, '.')}`, \n { percentUploaded: 0 }\n )\n },\n},\n {})\n\n\nreducer.options({\n payload: false\n});\n\n\n\n\nconst combinedReducer = (state, action) => {\n var nextState = reducer(state, action)\n return firestoreReducer(nextState,action)\n}\n\n\nexport default combinedReducer\n\n","import reducer from './reducer'\n\nexport default reducer\n","import dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\nimport { firebaseReducer } from 'react-redux-firebase'\nimport appReducer from './app'\nimport { connectRouter } from 'connected-react-router'\nimport firestoreReducer from './firestore'\n\n\nconst createRootReducer = (history) => {\n\n\n const routerReducer = connectRouter(history)\n\n const reducer = (state = {}, action) => {\n return {\n ...state,\n app: appReducer(state.app, action),\n firestore: firestoreReducer(state.firestore, action),\n firebase: firebaseReducer(state.firebase, action),\n router: routerReducer(state.router, action)\n }\n\n }\n\n\n return reducer\n\n}\n\nexport default createRootReducer\n\n","import { createStore, applyMiddleware } from 'redux';\nimport createRootReducer from './reducer'\nimport thunk from 'redux-thunk'\nimport { routerMiddleware } from 'connected-react-router'\nimport { composeWithDevTools } from 'redux-devtools-extension';\nimport { reduxFirestore, getFirestore } from 'redux-firestore';\nimport { getFirebase } from 'react-redux-firebase'\nimport { createHashHistory } from 'history'\nimport appActions from './app/actions'\n\nexport const history = createHashHistory()\n\nexport default function configureStore(initialState, firebase) {\n\n const rootReducer = createRootReducer(history)\n\n\n const store = createStore(rootReducer,\n initialState,\n composeWithDevTools(\n applyMiddleware(\n routerMiddleware(history),\n thunk.withExtraArgument({getFirestore, getFirebase})\n ),\n reduxFirestore(firebase)\n ));\n\n\n\n //var connectedRef = firebase.database().ref(\".info/connected\");\n\n //connectedRef.on(\"value\", function(snap) {\n //if (snap.val() === true) {\n //store.dispatch(appActions.setOnlineStatus(true))\n //} else {\n //store.dispatch(appActions.setOnlineStatus(false))\n //}\n //});\n\n firebase.firestore().enablePersistence()\n .catch((error) => {\n if (error === \"failed-precondition\") {\n alert(\"Multiple tabs open, offline data only works in one tab at a a time.\")\n } else if (error === \"unimplemented\") {\n alert(\"Cannot save offline on this browser.\")\n }\n });\n\n if (module.hot) {\n module.hot.accept('./reducer', () => {\n const nextRootReducer = createRootReducer(history)\n store.replaceReducer(nextRootReducer);\n });\n }\n\n return store;\n\n}\n","import React from \"react\"\nimport { Provider } from 'react-redux';\nimport { RootNode, configureStore, history } from '../apps/pawa_auditor'\nimport firebase from 'firebase/app'\nimport 'firebase/auth';\nimport 'firebase/database';\nimport 'firebase/firestore';\nimport 'firebase/storage';\nimport { ReactReduxFirebaseProvider } from 'react-redux-firebase';\nimport { createFirestoreInstance } from 'redux-firestore'\nimport { ConnectedRouter } from 'connected-react-router'\nimport 'react-router-modal/css/react-router-modal.css'\nimport { ModalContainer } from 'react-router-modal';\n\nconst rrfConfig = { useFirestoreForStorageMeta: true }\n\nexport default ({initialState, fbConfig}) => {\n firebase.initializeApp(fbConfig)\n firebase.firestore().settings({ experimentalForceLongPolling: true });\n\n const store = configureStore(initialState, firebase)\n\n return (\n \n \n \n \n \n \n
\n \n \n \n );\n}\n\n","const addEventListener = (el, eventName, handler) => {\n if (el.addEventListener) {\n el.addEventListener(eventName, handler);\n } else {\n el.attachEvent(\"on\" + eventName, function () {\n handler.call(el);\n });\n }\n};\n\nexport const addEventListeners = (selector, type, handler) => {\n const elements = document.querySelectorAll(selector);\n for (let i = 0; i < elements.length; i++) {\n addEventListener(elements[i], type, handler);\n }\n};\n\nconst removeEventListener = (el, eventName, handler) => {\n if (el.removeEventListener) {\n el.removeEventListener(eventName, handler);\n } else {\n el.detachEvent(\"on\" + eventName, function () {\n handler.call(el);\n });\n }\n};\n\nexport const removeEventListeners = (selector, type, handler) => {\n const elements = document.querySelectorAll(selector);\n for (let i = 0; i < elements.length; i++) {\n removeEventListener(elements[i], type, handler);\n }\n};\n\n//export const debounce = (func, wait, immediate) => {\n //let timeout;\n\n //return function executedFunction() {\n //const context = this;\n //const args = arguments;\n\n //const later = function () {\n //timeout = null;\n //if (!immediate) func.apply(context, args);\n //};\n\n //const callNow = immediate && !timeout;\n\n //clearTimeout(timeout);\n\n //timeout = setTimeout(later, wait);\n\n //if (callNow) func.apply(context, args);\n //};\n//};\n","import React, { useRef } from 'react';\nimport PropTypes from \"prop-types\"\nimport _ from 'lodashExtended';\nimport classNames from \"classnames\";\nimport CreatableSelect from 'react-select/creatable';\n\nvar CreateSelectInput = ({\n allErrors = {},\n value,\n onChange,\n subtext,\n placeholder,\n disabled = false,\n editable = false,\n label,\n name,\n optional = false,\n ...selectProps\n}) => {\n let errors = _.uniq(allErrors[name] || []);\n let hasError = _.isPresent(errors);\n const creatable = useRef(null);\n const handleBlur = () => {\n\n const select = creatable.current.select.select;\n if (select.state.focusedOption && select.props.inputValue.length > 1) {\n select.selectOption(select.state.focusedOption);\n }\n }\n\n var selectedOption = selectProps.options.filter((option) => option.value === value )\n if(_.isPresent(value) && _.isBlank(selectedOption)) {\n selectedOption = { value, label: value, __isNew__: true }\n }\n\n return (\n \n {label ? (\n
\n \n {label}\n \n
\n ) : null}\n {subtext ?
{subtext}
: null}\n
onChange(value,name)}\n />\n {_.map(errors, (error) => (\n \n {error} \n
\n ))}\n \n );\n};\n\nCreateSelectInput.propTypes = {\n name: PropTypes.string.isRequired,\n label: PropTypes.node,\n subtext: PropTypes.node,\n value: PropTypes.oneOfType([\n PropTypes.string,\n PropTypes.number,\n ]),\n options: PropTypes.arrayOf(PropTypes.shape({\n value: PropTypes.oneOfType([\n PropTypes.string,\n PropTypes.number,\n ]),\n label: PropTypes.node\n }))\n};\n\n\nCreateSelectInput.propTypes = {\n};\n\n\nexport default CreateSelectInput;\n\n\n\n\n\n\n","import React, { useState, useReducer } from \"react\";\nimport PropTypes from \"prop-types\";\nimport { connect } from \"react-redux\";\nimport _ from \"lodashExtended\";\nimport {\n TextAreaInput,\n CheckboxInput\n} from 'auditComponents'\nconst Checkbox = CheckboxInput.Checkbox\n\n\nimport CreateSelectInput from \"./CreateSelectInput\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { faPaperPlane, faCheck } from \"@fortawesome/free-solid-svg-icons\";\nimport { Btn } from \"sharedComponents\";\nimport { getCoworkerContacts } from \"../app/selectors\";\n//import { CheckboxInput, Checkbox } from \"./CheckboxInput\";\nimport { orderedSections } from \"./sections\";\nimport dotProp from \"dot-prop-immutable\";\nimport emailAddressCheck from \"email-addresses\";\nimport {\n ModalBox\n} from \"auditComponents\";\nimport { getHelp } from '../app/operations'\n\nconst d = dotProp;\n\nconst sectionIdsReducer = (sectionIds, { value, sectionId }) => {\n if (value) {\n return _(sectionIds).concat(sectionId).uniq().value();\n } else {\n return _.without(sectionIds, sectionId);\n }\n};\n\nvar GetHelpModal = ({ onSubmit, closeModal, coworkerContacts }) => {\n const [submited, setSubmit] = useState(false);\n const [comment, setComment] = useState();\n const [coworkerEmail, setCoworkerEmail] = useState();\n const [sectionIds, setSectionId] = useReducer(sectionIdsReducer, []);\n\n if (!submited) {\n\n const buttonsDisabled = _.isBlank(coworkerEmail) || _.isBlank(sectionIds);\n return (\n {\n onSubmit(coworkerEmail, sectionIds, comment);\n setSubmit(true);\n }}\n className=\"get-help-modal\"\n >\n ({ value, label })\n )}\n formatCreateLabel={(input) => `Send to '${input}'`}\n createOptionPosition=\"first\"\n onChange={(v) => setCoworkerEmail(v.replace(/\\s/g,''))}\n placeholder=\"Select or input a coworkers email\"\n />\n \n {_.map(orderedSections, ({ sectionId, title }) =>{ \n return(\n setSectionId({ value, sectionId })}\n />\n ) } \n )}\n \n setComment(v)}\n placeholder=\"Add your comment\"\n />\n \n );\n } else {\n return (\n \n \n
Help is on the way
\n
\n
\n A email has been sent to to {coworkerEmail} to ask for help. \n
\n
\n \n \n Close\n \n
\n \n );\n }\n};\n\nGetHelpModal.propTypes = {};\n\nconst mapStateToProps = (state, {}) => {\n return {\n coworkerContacts: getCoworkerContacts(state),\n };\n};\n\nconst mapDispatchToProps = (dispatch, {}) => {\n return {\n onSubmit: (coworkerEmail, sectionIds, comment) => { dispatch(getHelp(coworkerEmail, sectionIds, comment))},\n };\n};\n\nGetHelpModal = connect(mapStateToProps, mapDispatchToProps)(GetHelpModal);\n\nexport default GetHelpModal;\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport { connect } from \"react-redux\";\nimport _ from \"lodashExtended\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { faQuestionCircle } from \"@fortawesome/free-regular-svg-icons\";\nimport { Btn } from \"sharedComponents\";\nimport { useHistory, useRouteMatch } from \"react-router-dom\";\nimport GetHelpModal from \"./GetHelpModal\";\nimport { ModalRoute } from \"react-router-modal\";\n//import { isMobile } from \"react-device-detect\";\nimport { Portal } from \"react-portal\";\nimport { useMediaQuery } from \"react-responsive\";\n\n//import actions from '../slice/actions'\n//var {\n//} = actions\n\nvar NeedHelp = ({}) => {\n let history = useHistory();\n const isMobileMode = useMediaQuery({ maxWidth: 992 });\n\n var component;\n\n if (isMobileMode) {\n component = (\n \n history.push(`/getHelp`)} styles=\"btn nav\">\n Ask for help\n \n \n );\n } else {\n component = (\n \n
\n
\n Need help from\n a colleague?\n \n
\n Ask a colleague to complete a specific part(s) of the audit. This will send an e-mail link to your colleague to access this audit.\n
\n
\n history.push(`/getHelp`)}\n styles=\"outline-primary w-100\"\n className=\"w-100\"\n >\n Ask a colleague for help\n \n
\n
\n
\n );\n }\n\n return (\n \n \n {component}\n \n );\n};\n\nNeedHelp.propTypes = {};\n\n//const mapStateToProps = (state, {}) => {\n//return {\n//}\n//}\n\n//const mapDispatchToProps = (dispatch, {}) => {\n//return {\n//}\n//}\n\n//NeedHelp = connect(\n//mapStateToProps,\n//mapDispatchToProps\n//)(NeedHelp)\n\nexport default NeedHelp;\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport _ from \"lodashExtended\";\nimport { Btn } from \"sharedComponents\";\n\nvar SubmittedModal = ({afterSubmitPath}) => {\n\n return (\n \n
\n
\n
\n
Thank you for submitting your site audit.
\n
\n This report will be reviewed by Anenta and you'll have the ability to\n develop action items on any failed audit items that will be shown on\n your audit report\n
\n
\n
\n (window.location = afterSubmitPath)}\n className=\"w-phone-100 m-0\"\n styles=\"primary\"\n >\n Go to your Home Page\n \n
\n
\n );\n};\n\n\n\nSubmittedModal.propTypes = {\n afterSubmitPath: PropTypes.string.isRequired,\n}\n\nexport default SubmittedModal;\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport _ from \"lodashExtended\";\nimport { Btn } from \"sharedComponents\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { faPaperPlane } from \"@fortawesome/free-solid-svg-icons\";\n\nvar SubmitWarningModal = ({\n onSubmit,\n closeModal\n}) => {\n return (\n \n
\n
\n
Are you sure you want to Submit the Audit?
\n
\n
\n
\n Before you submit this audit please ensure that you provide all required information\n and that all attachments are related to the question and are clearly visible.\n Missing information or unclear images may affect your audit score\n
\n
\n
\n \n Back to Overview\n \n \n Submit Audit\n \n
\n
\n );\n};\n\nexport default SubmitWarningModal;\n","import React, { useEffect } from 'react';\nimport PropTypes from \"prop-types\"\nimport { connect } from 'react-redux';\nimport _ from 'lodashExtended';\nimport { orderedSectionSummaryViews } from './sections'\nimport SubmittedModal from './SubmittedModal'\nimport SubmitWarningModal from './SubmitWarningModal'\n\nimport {\n SubmitSummary\n} from 'auditComponents'\n\n\nexport default (props) => {\n return \n}\n","import { StatusSummary } from 'auditComponents';\nimport _ from 'lodashExtended';\nimport PropTypes from 'prop-types';\nimport React, { useEffect, useLayoutEffect, useState } from 'react';\nimport { isMobile } from 'react-device-detect';\nimport { connect } from 'react-redux';\nimport { firestoreConnect } from 'react-redux-firebase';\nimport { useMediaQuery } from 'react-responsive';\nimport { Route, Switch, useLocation } from 'react-router-dom';\nimport StickyBox from 'react-sticky-box';\nimport { compose } from 'redux';\nimport { Link } from 'sharedComponents';\n\nimport { addEventListeners, removeEventListeners } from '../app/helper';\nimport { goToSummaryPage, submitAudit } from '../app/operations';\nimport { areAllSectionsComplete, getSectionStatusById } from '../sections/selectors';\nimport { getAuditDocument } from '../wasteAudit/selectors';\nimport NeedHelp from './NeedHelp';\nimport sectionComponents, { orderedSectionIds } from './sections';\nimport SubmitSummary from './SubmitSummary';\n\nvar App = (props) => {\n const {\n allDataLoaded,\n wasteAudit,\n currentUser,\n guidebookUrl,\n } = props;\n\n const isMobileMode = useMediaQuery({ maxWidth: 992 });\n const location = useLocation();\n\n const [showSubmit, setShowSubmit] = useState(false);\n const [showSummaryBox, setShowSummaryBox] = useState(true);\n\n useEffect(() => {\n if (isMobile) {\n document.getElementById(\n \"dropdownMenuButtonNav\"\n ).innerHTML = ` `;\n }\n window.addEventListener(\"keyup\", function (event) {\n if (event.key === \"Enter\") {\n if (event.target.localName === \"textarea\") {\n return;\n }\n event.target.blur();\n }\n });\n\n return () => {\n window.removeEventListener(\"keyup\", () => {});\n };\n }, [isMobile]);\n\n const isBottom = (el) => {\n const height = window.innerHeight + 100;\n return el.getBoundingClientRect().bottom <= height;\n };\n\n const trackScrolling = _.debounce(\n () => {\n const wrappedElement = document.getElementById(\"main\");\n wrappedElement && isBottom(wrappedElement)\n ? setShowSubmit(true)\n : setShowSubmit(false);\n },\n 50,\n { maxWait: 200 }\n );\n\n useLayoutEffect(() => {\n if (isMobile) {\n addEventListeners(\"input\", \"focus\", (e) => {\n setShowSummaryBox(false);\n });\n\n addEventListeners(\"input\", \"blur\", (e) => {\n setShowSummaryBox(true);\n });\n\n return () => {\n removeEventListeners(\"input\", \"focus\");\n removeEventListeners(\"input\", \"blur\");\n };\n }\n }, [isMobile, wasteAudit]);\n\n useLayoutEffect(() => {\n if (isMobileMode) {\n setShowSummaryBox(location.pathname !== \"/submitSummary\");\n document.addEventListener(\"scroll\", trackScrolling);\n return () => {\n document.removeEventListener(\"scroll\", trackScrolling);\n };\n }\n }, [isMobileMode, wasteAudit]);\n\n if (wasteAudit) {\n return (\n \n \n \n \n \n \n \n
\n
\n
\n Duty of Care Waste Management Audit\n
\n
\n Welcome to your Waste Management Audit. This audit forms\n part of statutory requirements which you are required to\n hold evidence for. This online self audit has been developed\n in light of Covid 19 and the restrictions placed upon us for\n social distancing and to prevent unnecessary interactions\n through having a physical presence on sight.\n
\n
\n This audit complies with all aspects of a waste audit that\n should be conducted on an annual basis. Each section should\n be completed to the best of your abilities and by an\n individual competent in knowledge of waste management at\n your practice.\n
\n\n
\n
\n \n
\n\n
\n
\n Anenta have worked in conjunction with HEE to develop a\n standardised training package that encompasses all areas\n of waste from NHS strategy to correct waste segregation.\n Use the link below to access e-learning for health and\n search Healthcare Waste Management and Disposal. If you\n do not have an account feel free to register for this\n free service.\n
\n\n
\n \n http://portal.e-lfh.org.uk/Component/Details/763177\n \n
\n
\n
\n\n {guidebookUrl ? (\n
\n \n Please read the downloadable document below to get more\n information about what documents, images and other\n information that will be required to complete this\n audit. You may wish to gather some of this information\n prior to starting each section.\n
\n \n \n \n Self-Audit Guidebook.pdf\n \n
\n \n ) : null}\n
\n {_.map(sectionComponents, (Section, i) => (\n \n ))}\n \n
\n\n {!isMobileMode ? (\n
\n \n \n \n \n \n \n
\n ) : null}\n
\n
\n \n \n\n {isMobileMode && showSummaryBox ? (\n \n \n \n \n \n \n \n \n ) : null}\n \n );\n } else {\n return (\n \n );\n }\n};\n\nApp.propTypes = {\n auditDocumentId: PropTypes.string.isRequired,\n};\n\nconst mapStateToProps = (state, props) => {\n const { auditDocumentId, afterSubmitPath, currentUser, guidebookUrl } =\n state.app;\n\n return {\n auditDocumentId,\n wasteAudit: getAuditDocument(auditDocumentId, state),\n afterSubmitPath,\n currentUser,\n guidebookUrl,\n sectionStatusById: getSectionStatusById(state),\n allSectionsComplete: areAllSectionsComplete(state),\n };\n};\n\nconst mapDispatchToProps = (dispatch, ownProps) => {\n return {\n onSubmitAudit: (successPath) => dispatch(submitAudit(successPath)),\n goToSummaryPage: () => dispatch(goToSummaryPage()),\n };\n};\n\nApp = compose(\n connect(mapStateToProps, mapDispatchToProps),\n firestoreConnect(({ auditDocumentId }) => {\n return [\n {\n collection: \"waste_audits\",\n doc: auditDocumentId,\n },\n {\n collection: \"waste_audits\",\n doc: auditDocumentId,\n subcollections: [{ collection: \"sections\" }],\n storeAs: \"sections\", // make sure to include this\n },\n {\n collection: \"waste_audits\",\n doc: auditDocumentId,\n subcollections: [{ collection: \"rooms\" }],\n storeAs: \"rooms\", // make sure to include this\n orderBy: [\"createdAt\"],\n },\n {\n collection: \"waste_audits\",\n doc: auditDocumentId,\n subcollections: [{ collection: \"bins\" }],\n storeAs: \"bins\", // make sure to include this\n orderBy: [\"createdAt\"],\n },\n {\n collection: \"waste_audits\",\n doc: auditDocumentId,\n subcollections: [{ collection: \"bulkContainments\" }],\n storeAs: \"bulkContainments\", // make sure to include this\n orderBy: [\"createdAt\"],\n },\n ];\n })\n)(App);\n\nexport default App;\n","import actions from './actions'\nimport { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\n\nconst {\n //setOnlineStatus,\n} = actions\n\nconst reducer = createReducer({\n //[setOnlineStatus]: (app, { payload }) => {\n //return dotProp.set(app, 'online', payload)\n //}\n},\n{ })\n\nreducer.options({\n payload: false\n});\n\n\nexport default reducer\n\n","import reducer from './reducer'\n\nexport { default as appActions } from \"./actions\";\n\nexport default reducer\n","import { createReducer } from 'redux-act'\nimport dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\nimport { compose } from 'redux'\nimport { firestoreReducer } from 'redux-firestore';\n\nvar d = dotProp\n\nconst reducer = createReducer({\n ['@@reactReduxFirebase/FILE_UPLOAD_PROGRESS']: (firestore, action) => {\n return d.merge(\n firestore,\n `data.${_.replace(action.meta.options.storeProgressAt, /\\//g, '.')}`, \n { percentUploaded: action.payload.percent }\n )\n },\n ['@@reactReduxFirebase/FILE_UPLOAD_START']: (firestore, action) => {\n return d.merge(\n firestore,\n `data.${_.replace(action.payload.options.storeProgressAt, /\\//g, '.')}`, \n { percentUploaded: 0 }\n )\n },\n},\n {})\n\n\nreducer.options({\n payload: false\n});\n\n\n\n\nconst combinedReducer = (state, action) => {\n var nextState = reducer(state, action)\n return firestoreReducer(nextState,action)\n}\n\n\nexport default combinedReducer\n\n","import reducer from './reducer'\n\nexport default reducer\n","import dotProp from 'dot-prop-immutable'\nimport _ from 'lodashExtended'\nimport { firebaseReducer } from 'react-redux-firebase'\nimport appReducer from './app'\nimport { connectRouter } from 'connected-react-router'\nimport firestoreReducer from './firestore'\n\n\nconst createRootReducer = (history) => {\n\n\n const routerReducer = connectRouter(history)\n\n const reducer = (state = {}, action) => {\n return {\n ...state,\n app: appReducer(state.app, action),\n firestore: firestoreReducer(state.firestore, action),\n firebase: firebaseReducer(state.firebase, action),\n router: routerReducer(state.router, action)\n }\n\n }\n\n\n return reducer\n\n}\n\nexport default createRootReducer\n\n","import { createStore, applyMiddleware } from 'redux';\nimport createRootReducer from './reducer'\nimport thunk from 'redux-thunk'\nimport { routerMiddleware } from 'connected-react-router'\nimport { composeWithDevTools } from 'redux-devtools-extension';\nimport { reduxFirestore, getFirestore } from 'redux-firestore';\nimport { getFirebase } from 'react-redux-firebase'\nimport { createHashHistory } from 'history'\nimport appActions from './app/actions'\n\nexport const history = createHashHistory()\n\nexport default function configureStore(initialState, firebase) {\n\n const rootReducer = createRootReducer(history)\n\n\n const store = createStore(rootReducer,\n initialState,\n composeWithDevTools(\n applyMiddleware(\n routerMiddleware(history),\n thunk.withExtraArgument({getFirestore, getFirebase})\n ),\n reduxFirestore(firebase)\n ));\n\n\n\n //var connectedRef = firebase.database().ref(\".info/connected\");\n\n //connectedRef.on(\"value\", function(snap) {\n //if (snap.val() === true) {\n //store.dispatch(appActions.setOnlineStatus(true))\n //} else {\n //store.dispatch(appActions.setOnlineStatus(false))\n //}\n //});\n\n firebase.firestore().enablePersistence()\n .catch((error) => {\n if (error === \"failed-precondition\") {\n alert(\"Multiple tabs open, offline data only works in one tab at a a time.\")\n } else if (error === \"unimplemented\") {\n alert(\"Cannot save offline on this browser.\")\n }\n });\n\n if (module.hot) {\n module.hot.accept('./reducer', () => {\n const nextRootReducer = createRootReducer(history)\n store.replaceReducer(nextRootReducer);\n });\n }\n\n return store;\n\n}\n","import React from \"react\"\nimport { Provider } from 'react-redux';\nimport { RootNode, configureStore, history } from '../apps/auditor'\nimport firebase from 'firebase/app'\nimport 'firebase/auth';\nimport 'firebase/database';\nimport 'firebase/firestore';\nimport 'firebase/storage';\nimport { ReactReduxFirebaseProvider } from 'react-redux-firebase';\nimport { createFirestoreInstance } from 'redux-firestore'\nimport { ConnectedRouter } from 'connected-react-router'\nimport 'react-router-modal/css/react-router-modal.css'\nimport { ModalContainer } from 'react-router-modal';\n\nconst rrfConfig = { useFirestoreForStorageMeta: true } \n\nexport default ({initialState, fbConfig}) => {\n firebase.initializeApp(fbConfig)\n firebase.firestore().settings({ experimentalForceLongPolling: true });\n\n\n const store = configureStore(initialState, firebase)\n\n return (\n \n \n \n \n \n \n
\n \n \n \n );\n}\n\n","import React from 'react'\nimport createReactClass from 'create-react-class'\nimport classNames from 'classnames'\n\nvar CheckList = createReactClass({\n render: function() {\n var self = this\n var options = _.map(this.props.children, function(child, i) {\n\n return React.cloneElement(child, {\n key: i,\n onClick: self.handleSelect,\n selected: _.isEqual(child.props.value, self.props.selectedValue)\n }, child.props.children);\n\n\n })\n return (\n \n {options}\n
\n );\n },\n handleSelect: function(value) {\n this.props.onChange(value)\n }\n});\n\nvar CheckListOption = createReactClass({\n render: function() {\n var classes = classNames({\n 'list-group-item': true,\n 'active': this.props.selected\n });\n\n var style = this.props.selected ? {fontWeight: '600'} : {}\n\n var tick = this.props.selected ? (\n \n ) : null\n\n return (\n \n {tick}\n {this.props.children}\n \n );\n },\n handleClick: function(e) {\n e.preventDefault()\n this.props.onClick(this.props.value)\n }\n});\n\n\nexport default {\n List: CheckList,\n ListOption: CheckListOption\n}\n","import React from 'react'\nimport ReactDOM from 'react-dom'\nimport createReactClass from 'create-react-class'\nimport PropTypes from 'prop-types'\n\nvar Counter = createReactClass({\n propTypes: {\n displayAbsoluteNumber: PropTypes.bool\n },\n\tgetDefaultProps: function() {\n\t\treturn {\n\t\t\tmax: 1000,\n\t\t\tmin: -1000\n\t\t}\n\t},\n\trender: function() {\n\n\t\tvar moreClass = 'more badge ' + (this.maxReached() ? 'disabled' : '')\n\t\tvar lessClass = 'less badge ' + (this.minReached() ? 'disabled' : '')\n\n\t\treturn \n\t\t\t{ this.props.displayAbsoluteNumber ? Math.abs(this.props.count) : this.props.count } \n\t\t\t \n\t\t\t \n\t\t \n\n\t},\n\tmoreHandler: function() {\n var oldCount = this.props.count\n var newCount = this.props.count + 1\n\t\tthis.props.changeHandler(1, newCount, oldCount)\n\t},\n\tlessHandler: function() {\n var oldCount = this.props.count\n var newCount = this.props.count - 1\n\t\tthis.props.changeHandler(-1, newCount, oldCount)\n\t},\n\tmaxReached: function() {\n\t\treturn this.props.count >= this.props.max\n\t},\n\tminReached: function() {\n\t\treturn this.props.count <= this.props.min\n\t}\n})\n\n\nvar InputCounter = createReactClass({\n propTypes: {\n displayAbsoluteNumber: PropTypes.bool\n },\n\tgetDefaultProps: function() {\n\t\treturn {\n\t\t\tdescription: null,\n\t\t\tmax: 1000,\n\t\t\tmin: -1000,\n\t\t\twidth: 200\n\t\t}\n\t},\n\trender: function() {\n\n\t\tvar moreClass = 'more badge ' + (this.maxReached() ? 'disabled' : '')\n\t\tvar lessClass = 'less badge ' + (this.minReached() ? 'disabled' : '')\n\n\t\t// class for disabled more less button: non-active\n\n\t\tvar inputClass = 'zero'\n\t\tif(this.props.count > 0) {\n\t\t\tinputClass = 'greater-than-zero'\n\t\t} else if(this.props.count < 0) {\n\t\t\tinputClass = 'less-than-zero'\n\t\t}\n\n\t\treturn \n \t \t\n\t \t{this.props.name} \n\t \t \n \t \t \n\n \t \t\n \t \t\t \n \t \t\t \n \t \t\t \n\t \t \n\t
\n\n\t},\n\tmoreHandler: function() {\n var oldCount = this.props.count\n var newCount = this.props.count + 1\n\t\tthis.props.changeHandler(1, newCount, oldCount)\n\t},\n\tlessHandler: function() {\n var oldCount = this.props.count\n var newCount = this.props.count - 1\n\t\tthis.props.changeHandler(-1, newCount, oldCount)\n\t},\n\tmaxReached: function() {\n\t\treturn this.props.count >= this.props.max\n\t},\n\tminReached: function() {\n\t\treturn this.props.count <= this.props.min\n\t},\n componentDidMount: function() {\n if(!_.isNull(this.props.description)) {\n \t$(ReactDOM.findDOMNode(this)).popover()\n }\n },\n componentWillUnmount: function() {\n if(!_.isNull(this.props.description)) {\n \t$(ReactDOM.findDOMNode(this)).popover('destroy')\n }\n }\n})\n\n\n\nexport default {\n Counter: Counter,\n InputCounter: InputCounter\n}\n","import React from 'react'\nimport ReactDOM from 'react-dom'\nimport createReactClass from 'create-react-class'\nimport PropTypes from 'prop-types'\n\nvar DatePicker = createReactClass({\n getDefaultProps: function() {\n return {\n width: 3,\n label: null,\n displayFormat: 'dddd, Do MMMM YYYY'\n };\n },\n render: function() {\n\n var label = _.isString(this.props.label) ? {this.props.label} : null\n var successIcon = moment.isMoment(this.props.date) ? : null\n var placeholder = this.props.placeholder ? this.props.placeholder : \"select date...\"\n\n return (\n
\n
\n {label}\n \n {successIcon}\n
\n
\n
)\n },\n\n componentDidMount: function() {\n\n this.setState({\n picker: $(ReactDOM.findDOMNode(this)).find('input').datetimepicker({\n useCurrent: false,\n minDate: this.props.minDate,\n maxDate: this.props.maxDate\n })\n }, function() {\n\n var input = $($(ReactDOM.findDOMNode(this)).find('input'), this)\n\n input.on('dp.change', $.proxy(function(ev) {\n var date = this.state.picker.data(\"DateTimePicker\").date()\n if(_.isObject(date)) {\n input.closest('.form-group').addClass('has-success')\n this.props.onChange(date)\n }\n }, this ))\n\n if(_.isNull(this.props.date)) {\n input.val('')\n }\n\n })\n },\n componentWillReceiveProps: function(nextProps) {\n var self = this\n var input = $($(ReactDOM.findDOMNode(self)).find('input'), self)\n var newDate = nextProps.date ? moment(nextProps.date).format(nextProps.displayFormat) : ''\n input.val(newDate)\n }\n})\n\n\nexport default DatePicker\n","import React from 'react'\nimport ReactDOM from 'react-dom'\nimport createReactClass from 'create-react-class'\nimport PropTypes from 'prop-types'\n\nvar ReactSelect2 = createReactClass({\n\n propTypes: {\n // Array of components to be placed into the select\n children: PropTypes.array,\n name: PropTypes.string,\n multiple: PropTypes.bool,\n // The initial selected value; one of the option children should have a\n // matching value=\"...\"\n // defaultValue: PropTypes.string,\n // Callback executed when the selected value changes; receives a single\n // jQuery event object `e` from select2; `e.target` refers to the real\n // element and `e.val` refers to the new selected value\n onChange: PropTypes.func\n },\n\n getDefaultProps: function() {\n \treturn {\n \t\tplaceholder: null,\n \t\textraClass: 'input-sm'\n \t}\n },\n\n render: function() {\n\n \tvar blankOption = this.props.placeholder ? (\n \t\t \n \t) : null\n\n \tvar width = this.props.width || 'auto'\n\n return \n \t{blankOption}\n \t{this.props.children}\n \t\t \n },\n\n componentDidMount: function() {\n\t\tvar rootNode = $(ReactDOM.findDOMNode(this))\n\n rootNode.select2({minimumResultsForSearch: 15, allowClear: true, placeholder: this.props.placeholder})\n rootNode.on(\"change\", this._handleChange)\n\n if (this.props.defaultValue != null) { rootNode.select2(\"val\", this.props.defaultValue) }\n },\n\n\tcomponentDidUpdate: function() {\n\t\tvar rootNode = $(ReactDOM.findDOMNode(this))\n\t\trootNode.select2(\"val\", this.props.defaultValue)\n\t\trootNode.select2({placeholder: this.props.placeholder, minimumResultsForSearch: 15, allowClear: true })\n\t},\n\n componentWillUnmount: function() {\n $(ReactDOM.findDOMNode(this)).select2(\"destroy\")\n },\n\n _handleChange: function(e) {\n this.props.onChange && this.props.onChange(e)\n }\n});\n\n\nexport default ReactSelect2\n","import React from 'react'\nimport ReactLinkedStateMixin from 'react-addons-linked-state-mixin'\nimport ReactSelect2 from './select2'\nimport createReactClass from 'create-react-class'\nimport PropTypes from 'prop-types'\n\nvar FormGroup = createReactClass({\n getDefaultProps: function() {\n return {\n name: null,\n required: false,\n label: null,\n hint: null,\n hintPosition: 'bottom',\n errorMessage: null,\n visible: true\n };\n },\n render: function() {\n var errorMessage = null\n\n if(_.isString(this.props.errorMessage)){\n errorMessage = this.props.errorMessage\n } else if(_.isArray(this.props.errorMessage)){\n errorMessage = _(this.props.errorMessage).join(', ')\n }\n\n var labelEl = _.isString(this.props.label) ? (\n {this.props.label} {this.props.required ? : null} \n ) : null\n\n var error = errorMessage ? (\n {errorMessage}
\n ) : null\n\n var hint = this.props.hint && !errorMessage ? (\n {this.props.hint}
\n ) : null\n\n var hintTop = null\n var hintBottom = null\n\n if(this.props.hintPosition == 'top') { hintTop = hint } else { hintBottom = hint }\n\n return(\n \n {labelEl}\n {hintTop}\n
\n {this.props.children}\n
\n {error}\n {hintBottom}\n
\n );\n }\n});\n\n\n\nvar TextField = createReactClass({\n mixins: [ReactLinkedStateMixin],\n getDefaultProps: function() {\n return {\n disabled: false\n };\n },\n getInitialState: function() {\n return { value: this.props.value }\n },\n componentWillReceiveProps(nextProps) {\n var valueLink = this.linkState('value')\n if(nextProps.value != valueLink.value) {\n valueLink.requestChange(nextProps.value)\n }\n },\n render: function() {\n var self = this\n var valueLink = self.linkState('value')\n\n var handleChange = function(e) {\n valueLink.requestChange(e.target.value)\n self.props.onChange(e)\n };\n\n return(\n \n );\n }\n});\n\n\nvar PasswordField = createReactClass({\n getDefaultProps: function() {\n return {\n disabled: false\n };\n },\n render: function() {\n return(\n \n );\n },\n handleChange: function(event) {\n this.props.onChange(event)\n }\n});\n\n\nvar TextArea = createReactClass({\n mixins: [ReactLinkedStateMixin],\n getDefaultProps: function() {\n return {\n disabled: false\n };\n },\n getInitialState: function() {\n return { value: this.props.value }\n },\n componentWillReceiveProps(nextProps) {\n var valueLink = this.linkState('value')\n if(nextProps.value != valueLink.value) {\n valueLink.requestChange(nextProps.value)\n }\n },\n render: function() {\n var self = this\n var valueLink = self.linkState('value')\n\n var handleChange = function(e) {\n valueLink.requestChange(e.target.value)\n self.props.onChange(e)\n };\n\n return(\n