Commit e11735d7 authored by Andrew Hrdy's avatar Andrew Hrdy

Cache the alert ID's that have been viewed, show number of unread alerts in corner.

parent c6eb5df3
......@@ -3,6 +3,7 @@ export const SET_FACILITIES = 'SET_FACILITIES';
export const GET_FACILITIES = 'GET_FACILITIES';
export const SET_ALERTS = 'SET_ALERTS';
export const GET_ALERTS = 'GET_ALERTS';
export const VIEW_ALERT = 'VIEW_ALERT';
export const SET_SELECTED_FACILITY = 'SET_SELECTED_FACILITY';
export const SET_SEARCH_TERM = 'SET_SEARCH_TERM';
export const SET_CAMPUS_REGION = 'SET_CAMPUS_REGION';
......
import {GET_ALERTS, GET_FACILITIES, SET_ALERTS, SET_FACILITIES, SORT_BY_FAVORITES} from './action-types';
import {GET_ALERTS, GET_FACILITIES, SET_ALERTS, SET_FACILITIES, SORT_BY_FAVORITES, VIEW_ALERT} from './action-types';
const API_GET_FACILITIES = 'https://api.srct.gmu.edu/whatsopen/v2/facilities/';
const API_GET_ALERTS = 'https://api.srct.gmu.edu/whatsopen/v2/alerts/?ordering=urgency_tag';
......@@ -59,13 +59,43 @@ export const getAlerts = () => (dispatch) => {
return res.json();
}).then((json) => {
dispatch(setAlerts(JSON.stringify(json)));
dispatch(setAlerts(json));
});
};
export const setAlerts = (alerts) => {
const viewedAlerts = JSON.parse(localStorage.getItem('viewedAlerts'));
if (viewedAlerts) {
alerts.forEach((alert) => {
alert['viewed'] = viewedAlerts.includes(alert.id);
});
}
return {
type: SET_ALERTS,
alerts: JSON.parse(alerts)
alerts: alerts
};
};
export const viewAlert = (alert) => {
try {
let viewedAlerts = JSON.parse(localStorage.getItem('viewedAlerts'));
if (!viewedAlerts) {
viewedAlerts = [];
}
if (!viewedAlerts.includes(alert.id)) {
viewedAlerts.push(alert.id);
}
localStorage.setItem('viewedAlerts', JSON.stringify(viewedAlerts));
} catch (e) {
//Empty
}
return {
type: VIEW_ALERT,
alert
};
};
......@@ -39,8 +39,10 @@ class CustomAppBar extends React.Component {
What's Open
</Typography>
</div>
<AlertContainer/>
<div className={'app-bar-search-menu'}>
<div className={'app-bar-right-section'}>
<div className={'app-bar-alert-container'}>
<AlertContainer/>
</div>
<SearchBar onSearchExpand={() => this.setState({
isSearchExpanded: true
})}
......
import React from 'react';
import {findDOMNode} from 'react-dom';
import Button from 'material-ui/Button';
import IconButton from 'material-ui/IconButton';
import Popover from 'material-ui/Popover';
import Alert from '../components/Alert';
import NotificationsIcon from 'material-ui-icons/Notifications';
import Typography from 'material-ui/Typography';
import {connect} from 'react-redux';
import {viewAlert} from '../actions/api';
class AlertContainer extends React.Component {
......@@ -20,6 +22,7 @@ class AlertContainer extends React.Component {
this.setState({
isOpen: true
});
this.props.alerts.forEach((alert) => this.props.viewAlert(alert));
};
handleClose = () => {
......@@ -44,12 +47,20 @@ class AlertContainer extends React.Component {
render() {
const {alerts} = this.props;
const activeAlerts = alerts.filter(this.isAlertActive);
return (
<div>
<Button fab mini color={'primary'} ref={this.handleBtnRef} onClick={this.handleOpen}>
<NotificationsIcon/>
</Button>
<IconButton color={'primary'} ref={this.handleBtnRef} onClick={this.handleOpen}>
{activeAlerts.filter((alert) => !alert.viewed).length !== 0 &&
<span className={'alert-container-number'}>
<Typography type={'caption'} className={'alert-container-number-text'}>
{activeAlerts.length}
</Typography>
</span>}
<NotificationsIcon>
</NotificationsIcon>
</IconButton>
<Popover
open={this.state.isOpen}
anchorEl={this.state.anchorEl}
......@@ -63,9 +74,9 @@ class AlertContainer extends React.Component {
}}
onClose={this.handleClose}>
<div className={'alert-container-popover'}>
{alerts.filter(this.isAlertActive).map((alert) => {
{activeAlerts.map((alert) => {
return (
<Alert key={alert.id} alert={alert} />
<Alert key={alert.id} alert={alert}/>
);
})}
</div>
......@@ -82,4 +93,6 @@ function mapStateToProps(state) {
};
}
export default connect(mapStateToProps)(AlertContainer);
export default connect(mapStateToProps, {
viewAlert
})(AlertContainer);
import {GET_ALERTS, GET_FACILITIES, SET_ALERTS, SET_FACILITIES, SORT_BY_FAVORITES} from '../actions/action-types';
import {
GET_ALERTS,
GET_FACILITIES,
SET_ALERTS,
SET_FACILITIES,
SORT_BY_FAVORITES,
VIEW_ALERT
} from '../actions/action-types';
import cloneDeep from 'lodash/cloneDeep';
const defaultFacilityState = {
......@@ -51,6 +58,16 @@ export const alerts = (state = [], action) => {
return state;
case SET_ALERTS:
return [...state, ...action.alerts];
case VIEW_ALERT:
const index = state.findIndex((alert) => alert.id === action.alert.id);
const alert = cloneDeep(state[index]);
alert.viewed = true;
const stateClone = state.slice();
stateClone[index] = alert;
return stateClone;
default:
return state;
}
......
......@@ -15,7 +15,7 @@
color: #354052;
}
.app-bar-logo-name, .app-bar-search-menu {
.app-bar-logo-name, .app-bar-right-section {
display: flex;
align-items: center;
}
......@@ -54,7 +54,7 @@
}
.app-bar-search-expanded {
.app-bar-logo, .app-bar-title, .app-bar-menu-button, .app-bar-link-container {
.app-bar-logo, .app-bar-title, .app-bar-alert-container, .app-bar-menu-button, .app-bar-link-container {
display: none !important;
}
}
......
.alert-container-popover {
max-width: 500px;
max-width: 450px;
}
.alert-container-number {
position: absolute;
top: 3px;
right: 5px;
background-color: #FF0000;
padding: 4px;
border-radius: 100%;
height: 10px;
width: 10px;
}
.alert-container-number-text {
color: rgba(255, 255, 255, 1) !important;
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment