diff --git a/bin/eu-eea-e-prtr.awk b/bin/eu-eea-e-prtr.awk new file mode 100755 index 0000000..afaa839 --- /dev/null +++ b/bin/eu-eea-e-prtr.awk @@ -0,0 +1,14 @@ +# cat dbo.PUBLISH_FACILITYREPORT.csv| ./eu-eea-e-prtr.awk | mongoimport -d "fuegos" -c "industries" + +gawk -F',' 'NR>1 { \ + gsub(/"/,"",$6); + gsub(/"/,"",$5); + gsub(/\t/,"",$6); + gsub(/\t/,"",$5); + gsub(/\x1a/,"",$5); + gsub(/\x1a/,"",$6); + lon = $14+0; + lat = $13+0; + if (lon != 0 && lat != 0 && lon > -180 && lon < 180 && lat >= -90 && lat <= 90) + printf("{name:\"%s, %s\",geo:{type:\"Point\",coordinates:[%s,%s]},registry:\"1\"}\n" \ + ,$6,$5,lon,lat)}' diff --git a/bin/us-epa-frs.awk b/bin/us-epa-frs.awk new file mode 100755 index 0000000..56aec61 --- /dev/null +++ b/bin/us-epa-frs.awk @@ -0,0 +1,10 @@ +# cat NATIONAL_SINGLE.CSV| ./us-epa-frs.awk | mongoimport -d "fuegos" -c "industries" + +gawk -F',' 'NR>1{ \ + gsub(/"/,"",$33); + gsub(/"/,"",$32); + gsub(/"/,"",$3); + gsub(/\t/,"",$3); + lon = $33+0; + lat = $32+0; + if (lon != 0 && lat != 0 && lon > -180 && lon < 180 && lat >= -90 && lat <= 90) { printf("{name:\"%s\",geo:{type:\"Point\",coordinates:[%s,%s]},registry:\"2\"}\n",name,lon,lat)}}' diff --git a/imports/api/ActiveFires/server/publications.js b/imports/api/ActiveFires/server/publications.js index 6fd66eb..c6de899 100644 --- a/imports/api/ActiveFires/server/publications.js +++ b/imports/api/ActiveFires/server/publications.js @@ -5,7 +5,9 @@ import { Meteor } from 'meteor/meteor'; import { check } from 'meteor/check'; import { NumberBetween } from '/imports/modules/server/other-checks'; -import { whichAreFalsePositives } from '/imports/api/FalsePositives/server/publications'; +import { whichAreFalsePositives, firesUnion } from '/imports/api/FalsePositives/server/publications'; +import FalsePositives from '/imports/api/FalsePositives/FalsePositives'; +import Industries from '/imports/api/Industries/Industries'; import ActiveFires from '../ActiveFires'; const counter = new Counter('countActiveFires', ActiveFires.find({})); @@ -37,8 +39,10 @@ const activefires = (northEastLng, northEastLat, southWestLng, southWestLat, wit // console.log(`Fires total: ${fires.count()}`); if (withMarks && fires.fetch().length > 0) { - const falsePos = whichAreFalsePositives(fires); - return [fires, falsePos]; + const union = firesUnion(fires); + const falsePos = whichAreFalsePositives(FalsePositives, union); + const industries = whichAreFalsePositives(Industries, union); + return [fires, falsePos, industries]; } return fires; diff --git a/imports/api/FalsePositives/server/publications.js b/imports/api/FalsePositives/server/publications.js index 69ab992..659c2d4 100644 --- a/imports/api/FalsePositives/server/publications.js +++ b/imports/api/FalsePositives/server/publications.js @@ -7,6 +7,7 @@ import { check } from 'meteor/check'; import { NumberBetween } from '/imports/modules/server/other-checks'; import L from 'leaflet-headless'; import calcUnion from '/imports/ui/components/Maps/SubsUnion/Unify'; +import Industries from '/imports/api/Industries/Industries'; import FalsePositives from '../FalsePositives'; const counter = new Counter('countFalsePositives', FalsePositives.find({})); @@ -15,18 +16,21 @@ Meteor.publish('falsePositivesTotal', function total() { return counter; }); -export const whichAreFalsePositives = (fires) => { +export const firesUnion = (fires) => { const group = new L.FeatureGroup(); const remap = fires.fetch().map(function remap(doc) { // default scan: 1 for neightbor alerts return { location: { lat: doc.lat, lon: doc.lon }, distance: doc.scan || 1 }; }); - const result = calcUnion(remap, group, sub => sub); + const union = calcUnion(remap, group, sub => sub); + return union; +}; - const falsePos = FalsePositives.find({ +export const whichAreFalsePositives = (collection, union) => { + const result = collection.find({ geo: { $geoWithin: { - $geometry: result[0].geometry + $geometry: union[0].geometry } } }, { @@ -40,11 +44,11 @@ export const whichAreFalsePositives = (fires) => { /* console.log(`False positive total: ${falsePos.count()}`); console.log(`False positives: ${JSON.stringify(falsePos.fetch())}`); */ - return falsePos; + return result; }; -const falsePositives = (northEastLng, northEastLat, southWestLng, southWestLat) => { - const fires = FalsePositives.find({ +const find = (collection, northEastLng, northEastLat, southWestLng, southWestLat) => { + const fires = collection.find({ geo: { $geoWithin: { $box: [ @@ -60,19 +64,6 @@ const falsePositives = (northEastLng, northEastLat, southWestLng, southWestLat) // when: 1, fireId: 1 } - }).serverTransform(function transformDoc(odoc) { - const doc = odoc; - // Destructuring gives me an error: "Cannot destructure property `geo` of 'undefined'" - const geo = doc.geo; - if (geo) { - doc.lat = geo.coordinates[1]; - doc.lon = geo.coordinates[0]; - } - doc._id = doc.fireId; - doc.id = doc.fireId; - delete doc.geo; - // console.log(doc); - return doc; }); // console.log(`Fires total: ${fires.count()}`); return fires; @@ -85,5 +76,15 @@ Meteor.publishTransformed('falsePositivesMyloc', function falsePositivesInMyLoc( check(southWestLng, NumberBetween(-180, 180)); check(northEastLat, NumberBetween(-90, 90)); - return falsePositives(northEastLng, northEastLat, southWestLng, southWestLat); + return find(FalsePositives, northEastLng, northEastLat, southWestLng, southWestLat); +}); + +Meteor.publishTransformed('industriesMyloc', function industriesInMyLoc(northEastLng, northEastLat, southWestLng, southWestLat) { + // latitude -90 and 90 and the longitude between -180 and 180 + check(northEastLng, NumberBetween(-180, 180)); + check(southWestLat, NumberBetween(-90, 90)); + check(southWestLng, NumberBetween(-180, 180)); + check(northEastLat, NumberBetween(-90, 90)); + + return find(Industries, northEastLng, northEastLat, southWestLng, southWestLat); }); diff --git a/imports/api/Fires/server/publications.js b/imports/api/Fires/server/publications.js index 1dba8dc..96d6a85 100644 --- a/imports/api/Fires/server/publications.js +++ b/imports/api/Fires/server/publications.js @@ -9,7 +9,10 @@ import NodeGeocoder from 'node-geocoder'; import { gmapServerKey } from '/imports/startup/server/IPGeocoder'; import ActiveFiresCollection from '/imports/api/ActiveFires/ActiveFires'; import FireAlertsCollection from '/imports/api/FireAlerts/FireAlerts'; -import { whichAreFalsePositives } from '/imports/api/FalsePositives/server/publications'; +import { whichAreFalsePositives, firesUnion } from '/imports/api/FalsePositives/server/publications'; +import FalsePositives from '/imports/api/FalsePositives/FalsePositives'; +import Industries from '/imports/api/Industries/Industries'; + import FiresCollection from '../Fires'; function findFire(unsealed) { @@ -115,8 +118,10 @@ Meteor.publish('fireFromId', function fireFromId(_id) { const fire = FiresCollection.find(new Meteor.Collection.ObjectID(_id)); if (fire.count() !== 0) { // console.info(`Archive fire found: ${_id}`); - const falsePos = whichAreFalsePositives(fire); - return [fire, falsePos]; + const union = firesUnion(fire); + const falsePos = whichAreFalsePositives(FalsePositives, union); + const industries = whichAreFalsePositives(Industries, union); + return [fire, falsePos, industries]; } console.info(`Fire not found: ${_id}`); // Not found in active fires! diff --git a/imports/api/Industries/Industries.js b/imports/api/Industries/Industries.js new file mode 100644 index 0000000..f77ab9d --- /dev/null +++ b/imports/api/Industries/Industries.js @@ -0,0 +1,39 @@ +/* eslint-disable consistent-return */ + +import { Mongo } from 'meteor/mongo'; +import SimpleSchema from 'simpl-schema'; +import LocationSchema from '/imports/api/Utility/LocationSchema.js'; + +const Industries = new Mongo.Collection('industries'); + +Industries.allow({ + insert: () => false, + update: () => false, + remove: () => false +}); + +Industries.deny({ + insert: () => true, + update: () => true, + remove: () => true +}); + +Industries.schema = new SimpleSchema({ + geo: LocationSchema, + name: { type: String, optional: true }, + registry: String +}); + +Industries.attachSchema(Industries.schema); + +export const industriesRemap = (odoc) => { + const doc = odoc; + const geo = doc.geo; + doc.lat = geo.coordinates[1]; + doc.lon = geo.coordinates[0]; + doc.id = doc._id; + delete doc.geo; + return doc; +}; + +export default Industries; diff --git a/imports/api/Industries/IndustryRegistries.js b/imports/api/Industries/IndustryRegistries.js new file mode 100644 index 0000000..5eec43b --- /dev/null +++ b/imports/api/Industries/IndustryRegistries.js @@ -0,0 +1,29 @@ +/* eslint-disable consistent-return */ + +import { Mongo } from 'meteor/mongo'; +import SimpleSchema from 'simpl-schema'; + +const IndustryRegistries = new Mongo.Collection('industryregistries', { idGeneration: 'MONGO' }); + +IndustryRegistries.allow({ + insert: () => false, + update: () => false, + remove: () => false +}); + +IndustryRegistries.deny({ + insert: () => true, + update: () => true, + remove: () => true +}); + +IndustryRegistries.schema = new SimpleSchema({ + name: String, + agency: String, + region: String + +}); + +IndustryRegistries.attachSchema(IndustryRegistries.schema); + +export default IndustryRegistries; diff --git a/imports/startup/server/migrations.js b/imports/startup/server/migrations.js index f420f82..3f77de7 100644 --- a/imports/startup/server/migrations.js +++ b/imports/startup/server/migrations.js @@ -7,6 +7,8 @@ import UserSubsToFiresCollection from '/imports/api/Subscriptions/Subscriptions' import FireAlertsCollection from '/imports/api/FireAlerts/FireAlerts'; import SiteSettings from '/imports/api/SiteSettings/SiteSettings'; import FalsePositives from '/imports/api/FalsePositives/FalsePositives'; +import Industries from '/imports/api/Industries/Industries'; +import IndustryRegistries from '/imports/api/Industries/IndustryRegistries'; Meteor.startup(() => { // https://github.com/percolatestudio/meteor-migrations @@ -127,6 +129,22 @@ Meteor.startup(() => { } }); + Migrations.add({ + version: 9, + up: function siteSettingsAddIndex() { + Industries._ensureIndex({ registry: 1 }); + Industries._ensureIndex({ geo: '2dsphere' }); + // https://www.eea.europa.eu/data-and-maps/data/member-states-reporting-art-7-under-the-european-pollutant-release-and-transfer-register-e-prtr-regulation-16 + IndustryRegistries.insert({ + _id: '1', name: 'E-PRTR', agency: 'EEA', region: 'EU' + }); + // https://www.epa.gov/enviro/epa-frs-facilities-state-single-file-csv-download + IndustryRegistries.insert({ + _id: '2', name: 'FRS', agency: 'EPA', region: 'US' + }); + } + }); + // Set createdAt in users & subs Migrations.migrateTo('latest'); diff --git a/imports/ui/components/Maps/FireCircleMark.js b/imports/ui/components/Maps/FireCircleMark.js index d90e312..e4a3460 100644 --- a/imports/ui/components/Maps/FireCircleMark.js +++ b/imports/ui/components/Maps/FireCircleMark.js @@ -1,22 +1,40 @@ -import React from 'react'; +import React, { Component } from 'react'; import { Circle } from 'react-leaflet'; import PropTypes from 'prop-types'; +import { onMarkClick } from './MarkListeners'; import FirePopup from './FirePopup'; -const FireCircleMark = ({ - lat, - lon, - nasa, - scan, - id, - when, - history, - t -}) => ( - - - -); + +class FireCircleMark extends Component { + constructor(props) { + super(props); + this.t = props.t; + this.onClick = this.onClick.bind(this); + } + + onClick() { + const { history, nasa, id } = this.props; + onMarkClick(history, nasa, id); + } + + render() { + const { + lat, + lon, + scan, + nasa, + id, + history, + when, + t + } = this.props; + return ( + + + + ); + } +} FireCircleMark.propTypes = { scan: PropTypes.number.isRequired, diff --git a/imports/ui/components/Maps/FireIconMark.js b/imports/ui/components/Maps/FireIconMark.js index 9de93b2..4f9ab4c 100644 --- a/imports/ui/components/Maps/FireIconMark.js +++ b/imports/ui/components/Maps/FireIconMark.js @@ -2,7 +2,8 @@ import React, { Component, Fragment } from 'react'; import { CircleMarker, Marker, Tooltip } from 'react-leaflet'; import PropTypes from 'prop-types'; -import { fireIconS, fireIconM, fireIconL, nFireIcon, industryIcon } from '/imports/ui/components/Maps/Icons'; +import { fireIconS, fireIconM, fireIconL, nFireIcon, industryIcon, regIndustryIcon } from '/imports/ui/components/Maps/Icons'; +import { onMarkClick } from './MarkListeners'; import { translate } from 'react-i18next'; import FirePopup from './FirePopup'; @@ -14,8 +15,8 @@ class FireIconMark extends Component { } onClick() { - // console.log('onClick fired'); - this.props.history.push(`/fire/${this.props.nasa ? 'active' : 'alert'}/${this.props.id}`); + const { history, nasa, id } = this.props; + onMarkClick(history, nasa, id); } // Some docs: @@ -36,22 +37,34 @@ class FireIconMark extends Component { id, history, falsePositives, + industries, when, t } = this.props; return (
- { !falsePositives && + { !falsePositives && !industries && } - { falsePositives && + { industries && + {t('Es una industria (fuente: registro oficial)')} + } + { /* disabled */ industries && false && } + { falsePositives && !industries && {t('Es una industria')} { /* disabled because was a past fire (and can be marked multiple times) */ false && } } - { !falsePositives && + { !falsePositives && !industries && } @@ -67,6 +80,7 @@ FireIconMark.propTypes = { scan: PropTypes.number, nasa: PropTypes.bool, falsePositives: PropTypes.bool.isRequired, + industries: PropTypes.bool.isRequired, id: PropTypes.object.isRequired, history: PropTypes.object.isRequired, when: PropTypes.instanceOf(Date), diff --git a/imports/ui/components/Maps/FireList.js b/imports/ui/components/Maps/FireList.js index ecf22f1..a5979d7 100644 --- a/imports/ui/components/Maps/FireList.js +++ b/imports/ui/components/Maps/FireList.js @@ -9,17 +9,17 @@ import FirePixel from '/imports/ui/components/Maps/FirePixel'; export default function FireList(props) { const { - fires, scale, useMarkers, nasa, t, history, falsePositives + fires, scale, useMarkers, nasa, t, history, falsePositives, industries } = props; const useMarks = useMarkers && scale; const usePixel = !nasa || !scale; /* console.log(`Using marks: ${useMarks}, using pixels: ${usePixel}`); */ let items; if (useMarks) { - items = fires.map(({ _id, ...otherProps }) => ()); - } else if (usePixel && !falsePositives) { + items = fires.map(({ _id, ...otherProps }) => ()); + } else if (usePixel && !falsePositives && !industries) { items = fires.map(({ _id, ...otherProps }) => ()); - } else if (!falsePositives) { + } else if (!falsePositives && !industries) { items = fires.map(({ _id, ...otherProps }) => ()); } return (
{items}
); @@ -31,6 +31,7 @@ FireList.propTypes = { useMarkers: PropTypes.bool.isRequired, nasa: PropTypes.bool.isRequired, falsePositives: PropTypes.bool.isRequired, + industries: PropTypes.bool.isRequired, history: PropTypes.object.isRequired, t: PropTypes.func.isRequired }; diff --git a/imports/ui/components/Maps/Icons.js b/imports/ui/components/Maps/Icons.js index 7b9ecdb..95adf71 100644 --- a/imports/ui/components/Maps/Icons.js +++ b/imports/ui/components/Maps/Icons.js @@ -36,6 +36,12 @@ export const industryIcon = new Leaflet.Icon({ iconAnchor: [16, 20] }); +export const regIndustryIcon = new Leaflet.Icon({ + iconUrl: '/industry-marker-reg.png', + iconSize: [32, 37], + iconAnchor: [16, 20] +}); + export const nFireIcon = new Leaflet.Icon({ iconUrl: '/n-fire-marker.png', iconSize: [16, 24], // size of the icon diff --git a/imports/ui/components/Maps/MarkListeners.js b/imports/ui/components/Maps/MarkListeners.js new file mode 100644 index 0000000..5a85b44 --- /dev/null +++ b/imports/ui/components/Maps/MarkListeners.js @@ -0,0 +1,4 @@ +export const onMarkClick = (history, nasa, id) => { + // console.log('onClick fired'); + history.push(`/fire/${nasa ? 'active' : 'alert'}/${id}`); +}; diff --git a/imports/ui/layouts/App/App.js b/imports/ui/layouts/App/App.js index 4011296..c8fd5fd 100644 --- a/imports/ui/layouts/App/App.js +++ b/imports/ui/layouts/App/App.js @@ -115,7 +115,8 @@ const App = props => ( - + {/* */} + diff --git a/imports/ui/pages/Fires/Fires.js b/imports/ui/pages/Fires/Fires.js index 5662a3c..6c3f528 100644 --- a/imports/ui/pages/Fires/Fires.js +++ b/imports/ui/pages/Fires/Fires.js @@ -21,6 +21,7 @@ import { dateLongFormat } from '/imports/api/Common/dates'; import '/imports/startup/client/comments'; import FalsePositiveTypes from '/imports/api/FalsePositives/FalsePositiveTypes'; import FalsePositivesCollection, { falsePositivesRemap } from '/imports/api/FalsePositives/FalsePositives'; +import IndustriesCollection, { industriesRemap } from '/imports/api/Industries/Industries'; import ShareIt from '/imports/ui/components/ShareIt/ShareIt'; import './Fires.scss'; @@ -76,6 +77,7 @@ class Fire extends React.Component { notfound, loading, fire, t } = this.props; if (Meteor.isDevelopment) console.log(`False positives total: ${this.props.falsePositives.length}`); + if (Meteor.isDevelopment) console.log(`Industries total: ${this.props.industries.length}`); /* console.log(`loading fire: ${loading}`); * console.log(`Not found fire: ${notfound}`); */ if (fire && fire.when) { @@ -109,7 +111,7 @@ class Fire extends React.Component { fillColor="red" fillOpacity={0.0} interactive={false} - radius={fire.scan ? fire.scan * 1000 : 300} + radius={fire.scan ? fire.scan * 500 : 300} ref={(circle) => { this.circle = circle; this.handleLeafletLoad(circle); }} /> @@ -121,6 +123,17 @@ class Fire extends React.Component { useMarkers nasa={false} falsePositives + industries={false} + /> + @@ -136,7 +149,7 @@ class Fire extends React.Component { {(fire.type !== 'vecinal') && - { this.props.falsePositives.length > 0 && + { (this.props.falsePositives.length > 0 || this.props.industries.length > 0) && Parece que este fuego no es un fuego forestal. @@ -196,6 +209,7 @@ Fire.propTypes = { loading: PropTypes.bool.isRequired, notfound: PropTypes.bool.isRequired, falsePositives: PropTypes.arrayOf(PropTypes.object).isRequired, + industries: PropTypes.arrayOf(PropTypes.object).isRequired, fromHash: PropTypes.bool.isRequired, active: PropTypes.bool.isRequired, alert: PropTypes.bool.isRequired, @@ -236,12 +250,14 @@ const FireContainer = withTracker(({ match }) => { /* console.log(`loading fire: ${loading}`); * console.log(`Not found fire: ${notfound}`); */ const falsePositives = FalsePositivesCollection.find().fetch().map(falsePositivesRemap); + const industries = IndustriesCollection.find().fetch().map(industriesRemap); return { loading, active, alert, fromHash, falsePositives, + industries, fire: FiresCollection.findOne(), notfound, when: subscription.ready() && FiresCollection.findOne() ? FiresCollection.findOne().when : null diff --git a/imports/ui/pages/FiresMap/FiresMap.js b/imports/ui/pages/FiresMap/FiresMap.js index 849ffe5..865b29c 100644 --- a/imports/ui/pages/FiresMap/FiresMap.js +++ b/imports/ui/pages/FiresMap/FiresMap.js @@ -27,6 +27,7 @@ import DefMapLayers from '/imports/ui/components/Maps/DefMapLayers'; import FromNow from '/imports/ui/components/FromNow/FromNow'; import ActiveFiresCollection from '/imports/api/ActiveFires/ActiveFires'; import FireAlertsCollection from '/imports/api/FireAlerts/FireAlerts'; +import IndustriesCollection, { industriesRemap } from '/imports/api/Industries/Industries'; import FalsePositivesCollection, { falsePositivesRemap } from '/imports/api/FalsePositives/FalsePositives'; import SiteSettings from '/imports/api/SiteSettings/SiteSettings'; import { isNotHomeAndMobile, isChrome } from '/imports/ui/components/Utils/isMobile'; @@ -187,6 +188,8 @@ class FiresMap extends React.Component { if (Meteor.isDevelopment) console.log(`False positives total: ${this.props.falsePositives.length}`); + if (Meteor.isDevelopment) console.log(`Industries total: ${this.props.industries.length}`); + return ( /* Large number of markers: https://stackoverflow.com/questions/43015854/large-dataset-of-markers-or-dots-in-leaflet/43019740#43019740 */ @@ -270,6 +273,17 @@ class FiresMap extends React.Component { useMarkers={this.state.useMarkers} nasa={false} falsePositives + industries={false} + /> + = MAXZOOM} + useMarkers={this.state.useMarkers} + nasa={false} + falsePositives={false} + industries /> } @@ -318,6 +334,7 @@ FiresMap.propTypes = { activefires: PropTypes.arrayOf(PropTypes.object).isRequired, firealerts: PropTypes.arrayOf(PropTypes.object).isRequired, falsePositives: PropTypes.arrayOf(PropTypes.object).isRequired, + industries: PropTypes.arrayOf(PropTypes.object).isRequired, lastCheck: PropTypes.instanceOf(Date), activefirestotal: PropTypes.number.isRequired, center: PropTypes.arrayOf(PropTypes.number), @@ -331,6 +348,10 @@ FiresMap.propTypes = { let geoInit = true; export default translate([], { wait: true })(withTracker(() => { + // const firesType = match.params.type; + // const withIndustries = firesType === 'with-industries'; + // console.log(`With industries: ${withIndustries}`); + let subscription; let alertSubscription; @@ -339,6 +360,7 @@ export default translate([], { wait: true })(withTracker(() => { const marksStored = store.get('firesmap_marks'); const showUnionStored = store.get('firesmap_showunion'); zoom.set(zoomStored || 8); + center.set(centerStored || [0, 0]); if (typeof marksStored === 'boolean') { marks.set(marksStored); } @@ -346,7 +368,7 @@ export default translate([], { wait: true })(withTracker(() => { showUnion.set(showUnionStored); } Meteor.autorun(() => { - if ((centerStored || geolocation.get()) && geoInit) { + if ((centerStored !== [0, 0] || geolocation.get()) && geoInit) { center.set(centerStored || geolocation.get()); // console.log(`Geolocation ${geolocation.get()}`); geoInit = false; @@ -367,16 +389,28 @@ export default translate([], { wait: true })(withTracker(() => { mapSize.get()[1].lng, mapSize.get()[1].lat ); + /* if (withIndustries) { + Meteor.subscribe( + 'industriesMyloc', + mapSize.get()[0].lng, + mapSize.get()[0].lat, + mapSize.get()[1].lng, + mapSize.get()[1].lat + ); + } */ } }); Meteor.subscribe('activefirestotal'); + const settingsSubs = Meteor.subscribe('settings'); const lastCheck = SiteSettings.findOne({ name: 'last-fire-check' }); const userSubs = SiteSettings.findOne({ name: 'subs-public-union' }); const userSubsBounds = SiteSettings.findOne({ name: 'subs-public-union-bounds' }); const fireAlerts = FireAlertsCollection.find().fetch(); const falsePositives = FalsePositivesCollection.find().fetch().map(falsePositivesRemap); + const industries = IndustriesCollection.find().fetch().map(industriesRemap); + return { loading: !subscription ? true : !(subscription.ready() && settingsSubs.ready() && alertSubscription.ready()), userSubs: userSubs ? userSubs.value : null, @@ -387,6 +421,7 @@ export default translate([], { wait: true })(withTracker(() => { activefirestotal: Counter.get('countActiveFires') + fireAlerts.length, firealerts: fireAlerts, falsePositives, + industries, lastCheck: lastCheck ? lastCheck.value : null, center: center.get(), marks: marks.get(), diff --git a/public/industry-marker-reg.png b/public/industry-marker-reg.png new file mode 100644 index 0000000..a73f6a0 Binary files /dev/null and b/public/industry-marker-reg.png differ diff --git a/public/locales/en/common.json b/public/locales/en/common.json index f8c1571..c1a927d 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -217,5 +217,7 @@ "About '{{appName}}'", "¿Vecindarios vigilando y combatiendo fuegos? ¿de qué va todo esto?": "Neighborhoods monitoring and fighting fires? What is all this about?", - "noActiveNeigFireInMap": "There are no fires recently reported by our users in this area." + "noActiveNeigFireInMap": "There are no fires recently reported by our users in this area.", + "Es una industria (fuente: registro oficial)": + "It's an industry (source: oficial register)" } diff --git a/public/locales/es/common.json b/public/locales/es/common.json index 73025d7..2b6eeaf 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -304,5 +304,7 @@ "Sobre '{{appName}}'", "¿Vecindarios vigilando y combatiendo fuegos? ¿de qué va todo esto?": "¿Vecindarios vigilando y combatiendo fuegos? ¿de qué va todo esto?", - "noActiveNeigFireInMap": "No hay fuegos notificados recientemente por nuestros usuarios/as en esta zona." + "noActiveNeigFireInMap": "No hay fuegos notificados recientemente por nuestros usuarios/as en esta zona.", + "Es una industria (fuente: registro oficial)": + "Es una industria (fuente: registro oficial)" }