diff --git a/src/containers/BuildingEvents/BuildingEventsTable.js b/src/containers/BuildingEvents/BuildingEventsTable.js
index c87cdac8a91994e53850f24f8cbc44a09acd53b6..ba278892f09723658776fbec4b4769b9e6b49db5 100644
--- a/src/containers/BuildingEvents/BuildingEventsTable.js
+++ b/src/containers/BuildingEvents/BuildingEventsTable.js
@@ -4,17 +4,20 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import {
Card, Table, Row, Col,
- ListGroup, ListGroupItem,
Collapse,
} from 'reactstrap';
import { Icon } from 'react-fa';
-import { loadEvents } from '../Event/actions';
+import { loadEvents, addSubscription, loadAlertSubscribers } from '../Event/actions';
import Loading from '../../components/Loading';
import ErrorAlert from '../../components/ErrorAlert';
class BuildingEventsTable extends Component {
- state = { eventsOpen: false }
+ state = {
+ eventsOpen: false,
+ // The ARN for the email
+ emailSubArn: null,
+ }
componentDidMount() {
this.props.loadEvents({
@@ -22,54 +25,122 @@ class BuildingEventsTable extends Component {
limit: this.props.limit,
order: 'desc',
});
+ this.props.loadAlertSubscribers({
+ 'building_id[]': this.props.buildingId,
+ });
}
- renderHeading = (heading) => {
- return (
-
-
- {heading}
-
-
-
- );
+ componentWillReceiveProps(nextProps) {
+ if (nextProps === this.props) {
+ return;
+ }
+ /* eslint-disable no-param-reassign */
+ if (
+ nextProps.events.alertSubscribersData !==
+ this.props.events.alertSubscribersData
+ ) {
+ const topics = nextProps.events.alertSubscribersData;
+ const emailSubArn = topics.reduce(
+ (outerAcc, topic) => {
+ if (topic.building_id === nextProps.buildingId) {
+ return topic.subscriptions.reduce(
+ (innerAcc, subscription) => {
+ if (
+ subscription.Protocol === 'email' &&
+ subscription.Endpoint === localStorage.emailAddress
+ ) {
+ return subscription.SubscriptionArn;
+ }
+ return innerAcc;
+ }, outerAcc,
+ );
+ }
+ return outerAcc;
+ }, null,
+ );
+ this.setState({ emailSubArn });
+ }
+
}
- renderSpaces = (spaces) => {
- return spaces.map(spc => (
-
- {spc.description} {spc.floor ? ` - device on floor ${spc.floor}` : ''}
-
- ));
+ subscribeToAlert = () => {
+ this.props.addSubscription({
+ building_id: this.props.buildingId,
+ sub_type: 'email',
+ sub_val: localStorage.emailAddress,
+ });
}
- renderApartments = () => {
- return this.props.events.map(apt => {
+ renderAlertSubscription = () => {
+ /* eslint-disable jsx-a11y/no-static-element-interactions */
+ if (this.props.events.alertSubscribersLoading) {
+ return (
+
+
+
+ );
+ }
+ if (this.props.events.alertSubscribersError) {
+ return (
+
+
+
+ );
+ }
+ if (this.state.emailSubArn === 'PendingConfirmation' || this.state.emailSubArn === 'pending confirmation') {
return (
-
+
+ {' '}
+ Pending Your Confirmation
+
+ );
+ }
+ if (this.state.emailSubArn === 'Deleted') {
+ return (
+
-
- Apartment {apt.number}
-
-
- {this.renderSpaces(apt.spaces)}
-
-
+
+ {' '}
+ Resubscribe to alerts
+
);
- });
- }
-
- renderArea = (incArea) => {
- return incArea.map(area => {
+ }
+ if (this.state.emailSubArn !== null) {
return (
-
- {this.renderSpaces(area.spaces)}
-
+
+
+ {' '}
+ Subscribed
+
);
- });
+ }
+
+ return (
+
+
+ {' '}
+ Subscribe to alerts
+
+ );
}
render() {
@@ -107,18 +178,26 @@ class BuildingEventsTable extends Component {
} else if (this.props.events.eventsData.length === 0) {
mainContent = 'Sorry, no events data for this building';
}
- /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
+ /* eslint-disable jsx-a11y/no-static-element-interactions */
return (
- (
- this.setState({ eventsOpen: !this.state.eventsOpen })
- )}
- style={{ cursor: 'pointer' }}
- >
- Recent Sensor Events {' '}
-
+
+
+ (
+ this.setState({ eventsOpen: !this.state.eventsOpen })
+ )}
+ style={{ cursor: 'pointer' }}
+ lg="8"
+ md="6"
+ sm="12"
+ >
+ Recent Sensor Events {' '}
+
+
+ {this.renderAlertSubscription()}
+
{mainContent}
@@ -132,6 +211,8 @@ class BuildingEventsTable extends Component {
BuildingEventsTable.propTypes = {
buildingId: PropTypes.string,
loadEvents: PropTypes.func,
+ addSubscription: PropTypes.func,
+ loadAlertSubscribers: PropTypes.func,
events: PropTypes.object, // eslint-disable-line
limit: PropTypes.number,
};
@@ -147,6 +228,8 @@ const mapStateToProps = state => ({
const mapDispatchToProps = dispatch => (
bindActionCreators({
loadEvents,
+ loadAlertSubscribers,
+ addSubscription,
}, dispatch)
);
diff --git a/src/containers/Event/actions.js b/src/containers/Event/actions.js
index 07b2c1ad75ccca7bd5550e017f1ebbea7e5fa72a..2d2604926f4c46c20a205d198ab3a1aa5752515c 100644
--- a/src/containers/Event/actions.js
+++ b/src/containers/Event/actions.js
@@ -2,6 +2,12 @@ import {
EVENTS_REQUESTED,
EVENTS_SUCCEEDED,
EVENTS_FAILED,
+ ALERT_SUBSCRIBERS_REQUESTED,
+ ALERT_SUBSCRIBERS_SUCCEEDED,
+ ALERT_SUBSCRIBERS_FAILED,
+ ADD_SUBSCRIPTION_REQUESTED,
+ ADD_SUBSCRIPTION_SUCCEEDED,
+ ADD_SUBSCRIPTION_FAILED,
} from './constants';
import { makeActionCreator } from '../../utils/reduxHelpers';
@@ -11,3 +17,10 @@ export const loadEvents = makeActionCreator(EVENTS_REQUESTED, 'filters');
export const eventsLoaded = makeActionCreator(EVENTS_SUCCEEDED, 'eventsData');
export const eventsFailed = makeActionCreator(EVENTS_FAILED, 'error');
+export const loadAlertSubscribers = makeActionCreator(ALERT_SUBSCRIBERS_REQUESTED, 'filters');
+export const alertSubscribersLoaded = makeActionCreator(ALERT_SUBSCRIBERS_SUCCEEDED, 'alertSubscribersData');
+export const alertSubscribersFailed = makeActionCreator(ALERT_SUBSCRIBERS_FAILED, 'error');
+
+export const addSubscription = makeActionCreator(ADD_SUBSCRIPTION_REQUESTED, 'payload');
+export const subscriptionAdded = makeActionCreator(ADD_SUBSCRIPTION_SUCCEEDED, 'subscription');
+export const subscriptionAddFailed = makeActionCreator(ADD_SUBSCRIPTION_FAILED, 'error');
diff --git a/src/containers/Event/constants.js b/src/containers/Event/constants.js
index cd55049a82f6032117c27b5ce3f09d32f618a9b9..26d960ee3633c21fcab36975a8423eae267bdf3a 100644
--- a/src/containers/Event/constants.js
+++ b/src/containers/Event/constants.js
@@ -1,4 +1,11 @@
-/* Retrieve Events */
export const EVENTS_REQUESTED = 'EVENTS_REQUESTED';
export const EVENTS_SUCCEEDED = 'EVENTS_SUCCEEDED';
export const EVENTS_FAILED = 'EVENTS_FAILED';
+
+export const ALERT_SUBSCRIBERS_REQUESTED = 'ALERT_SUBSCRIBERS_REQUESTED';
+export const ALERT_SUBSCRIBERS_SUCCEEDED = 'ALERT_SUBSCRIBERS_SUCCEEDED';
+export const ALERT_SUBSCRIBERS_FAILED = 'ALERT_SUBSCRIBERS_FAILED';
+
+export const ADD_SUBSCRIPTION_REQUESTED = 'ADD_SUBSCRIPTION_REQUESTED';
+export const ADD_SUBSCRIPTION_SUCCEEDED = 'ADD_SUBSCRIPTION_SUCCEEDED';
+export const ADD_SUBSCRIPTION_FAILED = 'ADD_SUBSCRIPTION_FAILED';
diff --git a/src/containers/Event/reducer.js b/src/containers/Event/reducer.js
index 567de9e77a925603cd2f71e155cd6370db66d1fc..136f7b8c8d17d1703f174162356ffbc3372931a0 100644
--- a/src/containers/Event/reducer.js
+++ b/src/containers/Event/reducer.js
@@ -2,12 +2,21 @@ import {
EVENTS_REQUESTED,
EVENTS_SUCCEEDED,
EVENTS_FAILED,
+ ALERT_SUBSCRIBERS_REQUESTED,
+ ALERT_SUBSCRIBERS_SUCCEEDED,
+ ALERT_SUBSCRIBERS_FAILED,
+ ADD_SUBSCRIPTION_REQUESTED,
+ ADD_SUBSCRIPTION_SUCCEEDED,
+ ADD_SUBSCRIPTION_FAILED,
} from './constants';
export const initState = {
eventsLoading: false,
eventsError: false,
eventsData: [],
+ alertSubscribersLoading: false,
+ alertSubscribersError: false,
+ alertSubscribersData: [],
};
export default (state = initState, action) => {
@@ -26,6 +35,55 @@ export default (state = initState, action) => {
case EVENTS_FAILED:
return { ...state, eventsLoading: false, eventsError: action.error };
+ case ALERT_SUBSCRIBERS_REQUESTED:
+ return { ...state, alertSubscribersLoading: true, alertSubscribersError: false };
+
+ case ALERT_SUBSCRIBERS_SUCCEEDED:
+ return {
+ ...state,
+ alertSubscribersLoading: false,
+ alertSubscribersError: false,
+ alertSubscribersData: action.alertSubscribersData.data,
+ };
+
+ case ALERT_SUBSCRIBERS_FAILED:
+ return { ...state, alertSubscribersLoading: false, alertSubscribersError: action.error };
+
+ case ADD_SUBSCRIPTION_REQUESTED:
+ return { ...state, alertSubscribersLoading: true, alertSubscribersError: false };
+
+ /* eslint-disable no-param-reassign */
+ case ADD_SUBSCRIPTION_SUCCEEDED:
+ return {
+ ...state,
+ alertSubscribersLoading: false,
+ alertSubscribersError: false,
+ alertSubscribersData: state.alertSubscribersData.map((topic) => {
+ if (topic.arn === action.subscription.data.topic_arn) {
+ let updated = false;
+ topic.subscriptions.map((subscriber) => {
+ if (subscriber.Endpoint === action.subscription.data.sub_val) {
+ subscriber.SubscriptionArn = action.subscription.data.subscription_arn;
+ updated = true;
+ }
+ return subscriber;
+ });
+ if (!updated) {
+ topic.subscriptions.push({
+ Endpoint: action.subscription.data.sub_val,
+ Protocol: action.subscription.data.sub_type,
+ SubscriptionArn: action.subscription.data.subscription_arn,
+ TopicArn: action.subscription.data.topic_arn,
+ });
+ }
+ }
+ return topic;
+ }),
+ };
+
+ case ADD_SUBSCRIPTION_FAILED:
+ return { ...state, alertSubscribersLoading: false, alertSubscribersError: action.error };
+
default:
return state;
}
diff --git a/src/containers/Event/sagas.js b/src/containers/Event/sagas.js
index bcb5b9a794d017e5c76efc2d3327496fb6633c44..52f8e82d5d57583a6fdbb6a5ec1fcae74c91533e 100644
--- a/src/containers/Event/sagas.js
+++ b/src/containers/Event/sagas.js
@@ -1,23 +1,49 @@
import { takeEvery } from 'redux-saga/effects';
import SagaRequests from '../../utils/sagaRequests';
-import { eventsURL } from '../../utils/restServices';
+import { eventsURL, alertSubscribersURL } from '../../utils/restServices';
import {
EVENTS_REQUESTED,
+ ALERT_SUBSCRIBERS_REQUESTED,
+ ADD_SUBSCRIPTION_REQUESTED,
} from './constants';
import {
eventsLoaded,
eventsFailed,
+ alertSubscribersLoaded,
+ alertSubscribersFailed,
+ subscriptionAdded,
+ subscriptionAddFailed,
} from './actions';
function* getEvents(action) {
yield SagaRequests.get(action, eventsURL, eventsLoaded, eventsFailed);
}
+function* getAlertSubscribers(action) {
+ yield SagaRequests.get(
+ action,
+ alertSubscribersURL,
+ alertSubscribersLoaded,
+ alertSubscribersFailed,
+ );
+}
+
+function* addSubscription(action) {
+ yield SagaRequests.post(
+ action,
+ alertSubscribersURL,
+ subscriptionAdded,
+ subscriptionAddFailed,
+ );
+}
+
function* eventsWatcher() {
yield takeEvery(EVENTS_REQUESTED, getEvents);
+ yield takeEvery(ALERT_SUBSCRIBERS_REQUESTED, getAlertSubscribers);
+ yield takeEvery(ADD_SUBSCRIPTION_REQUESTED, addSubscription);
}
export default eventsWatcher;
diff --git a/src/containers/Sensors/SensorGraph.js b/src/containers/Sensors/SensorGraph.js
index 3f74b8e1c45ed0d18a11214875db5165852ad68e..1a0c05344513c65c2a3392d21633afef8938540e 100644
--- a/src/containers/Sensors/SensorGraph.js
+++ b/src/containers/Sensors/SensorGraph.js
@@ -82,6 +82,7 @@ export class SensorGraph extends Component {
)
generateData = (props) => {
+ this.setState({ firstLoad: false });
if (this.sensorDataLoading(props)) {
return;
}
@@ -684,14 +685,12 @@ export class SensorGraph extends Component {
Sensor Data
-
- From
-
-
+ From
+
To
diff --git a/src/utils/restServices.js b/src/utils/restServices.js
index c7158fbf8d8dac5c91cdd97bf28b300c6421d4a7..3e763e1e41d8562ea92091575c2e8c6e371ea4ff 100644
--- a/src/utils/restServices.js
+++ b/src/utils/restServices.js
@@ -48,6 +48,7 @@ export const gatewayURL = `${iotService}/gateway/`;
export const sensewareNodeURL = `${iotService}/sensewarenode/`;
export const sensorImageURL = `${iotService}/sensorimage/`;
export const eventsURL = `${iotService}/event/`;
+export const alertSubscribersURL = `${iotService}/alertsubscription/`;
export const userURL = `${userService}/user/`;
export const userGroupsURL = `${userService}/usergroup/`;