Use global snackbar

This commit is contained in:
rjwats@gmail.com 2018-03-03 22:41:57 +00:00
parent 5ffe4ab235
commit 521462cf75
12 changed files with 70 additions and 60 deletions

View File

@ -2,11 +2,12 @@ import React, { Component } from 'react';
import AppRouting from './AppRouting'; import AppRouting from './AppRouting';
import SnackbarNotification from './components/SnackbarNotification';
import JssProvider from 'react-jss/lib/JssProvider'; import JssProvider from 'react-jss/lib/JssProvider';
import { create } from 'jss'; import { create } from 'jss';
import Reboot from 'material-ui/Reboot'; import Reboot from 'material-ui/Reboot';
import blueGrey from 'material-ui/colors/blueGrey'; import blueGrey from 'material-ui/colors/blueGrey';
import indigo from 'material-ui/colors/indigo'; import indigo from 'material-ui/colors/indigo';
import orange from 'material-ui/colors/orange'; import orange from 'material-ui/colors/orange';
@ -43,8 +44,10 @@ class App extends Component {
return ( return (
<JssProvider jss={jss} generateClassName={generateClassName}> <JssProvider jss={jss} generateClassName={generateClassName}>
<MuiThemeProvider theme={theme}> <MuiThemeProvider theme={theme}>
<SnackbarNotification>
<Reboot /> <Reboot />
<AppRouting /> <AppRouting />
</SnackbarNotification>
</MuiThemeProvider> </MuiThemeProvider>
</JssProvider> </JssProvider>
) )

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, {Fragment} from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles'; import { withStyles } from 'material-ui/styles';
import Snackbar from 'material-ui/Snackbar'; import Snackbar from 'material-ui/Snackbar';
@ -13,6 +13,20 @@ const styles = theme => ({
}); });
class SnackbarNotification extends React.Component { class SnackbarNotification extends React.Component {
constructor(props) {
super(props);
this.raiseNotification=this.raiseNotification.bind(this);
}
static childContextTypes = {
raiseNotification: PropTypes.func.isRequired
}
getChildContext = () => {
return {raiseNotification : this.raiseNotification};
};
state = { state = {
open: false, open: false,
message: null message: null
@ -29,15 +43,10 @@ class SnackbarNotification extends React.Component {
this.setState({ open: false }); this.setState({ open: false });
}; };
componentWillReceiveProps(nextProps){
if (nextProps.notificationRef){
nextProps.notificationRef(this.raiseNotification);
}
}
render() { render() {
const { classes } = this.props; const { classes } = this.props;
return ( return (
<Fragment>
<Snackbar <Snackbar
anchorOrigin={{ anchorOrigin={{
vertical: 'bottom', vertical: 'bottom',
@ -62,13 +71,25 @@ class SnackbarNotification extends React.Component {
</IconButton> </IconButton>
} }
/> />
{this.props.children}
</Fragment>
); );
} }
} }
SnackbarNotification.propTypes = { SnackbarNotification.propTypes = {
classes: PropTypes.object.isRequired, classes: PropTypes.object.isRequired
notificationRef: PropTypes.func.isRequired,
}; };
export default withStyles(styles)(SnackbarNotification); export default withStyles(styles)(SnackbarNotification);
export function withNotifier(WrappedComponent) {
return class extends React.Component {
static contextTypes = {
raiseNotification: PropTypes.func.isRequired
};
render() {
return <WrappedComponent raiseNotification={this.context.raiseNotification} {...this.props} />;
}
};
}

View File

@ -1,8 +1,8 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { AP_SETTINGS_ENDPOINT } from '../constants/Endpoints'; import { AP_SETTINGS_ENDPOINT } from '../constants/Endpoints';
import {withNotifier} from '../components/SnackbarNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import SnackbarNotification from '../components/SnackbarNotification';
import APSettingsForm from '../forms/APSettingsForm'; import APSettingsForm from '../forms/APSettingsForm';
import { simpleGet } from '../helpers/SimpleGet'; import { simpleGet } from '../helpers/SimpleGet';
import { simplePost } from '../helpers/SimplePost'; import { simplePost } from '../helpers/SimplePost';
@ -31,7 +31,7 @@ class APSettings extends Component {
simpleGet( simpleGet(
AP_SETTINGS_ENDPOINT, AP_SETTINGS_ENDPOINT,
this.setState, this.setState,
this.raiseNotification, this.props.raiseNotification,
"apSettings", "apSettings",
"apSettingsFetched" "apSettingsFetched"
); );
@ -42,7 +42,7 @@ class APSettings extends Component {
AP_SETTINGS_ENDPOINT, AP_SETTINGS_ENDPOINT,
this.state, this.state,
this.setState, this.setState,
this.raiseNotification, this.props.raiseNotification,
"apSettings", "apSettings",
"apSettingsFetched" "apSettingsFetched"
); );
@ -58,7 +58,6 @@ class APSettings extends Component {
const { apSettingsFetched, apSettings, errorMessage } = this.state; const { apSettingsFetched, apSettings, errorMessage } = this.state;
return ( return (
<SectionContent title="AP Settings"> <SectionContent title="AP Settings">
<SnackbarNotification notificationRef={(raiseNotification)=>this.raiseNotification = raiseNotification} />
<APSettingsForm apSettingsFetched={apSettingsFetched} apSettings={apSettings} errorMessage={errorMessage} <APSettingsForm apSettingsFetched={apSettingsFetched} apSettings={apSettings} errorMessage={errorMessage}
onSubmit={this.saveAPSettings} onReset={this.loadAPSettings} handleValueChange={this.wifiSettingValueChange} /> onSubmit={this.saveAPSettings} onReset={this.loadAPSettings} handleValueChange={this.wifiSettingValueChange} />
</SectionContent> </SectionContent>
@ -67,4 +66,4 @@ class APSettings extends Component {
} }
export default APSettings; export default withNotifier(APSettings);

View File

@ -11,7 +11,7 @@ import SettingsInputAntennaIcon from 'material-ui-icons/SettingsInputAntenna';
import DeviceHubIcon from 'material-ui-icons/DeviceHub'; import DeviceHubIcon from 'material-ui-icons/DeviceHub';
import ComputerIcon from 'material-ui-icons/Computer'; import ComputerIcon from 'material-ui-icons/Computer';
import SnackbarNotification from '../components/SnackbarNotification' import {withNotifier} from '../components/SnackbarNotification';
import SectionContent from '../components/SectionContent' import SectionContent from '../components/SectionContent'
import * as Highlight from '../constants/Highlight'; import * as Highlight from '../constants/Highlight';
@ -48,7 +48,6 @@ class APStatus extends Component {
this.setState = this.setState.bind(this); this.setState = this.setState.bind(this);
this.loadAPStatus = this.loadAPStatus.bind(this); this.loadAPStatus = this.loadAPStatus.bind(this);
this.raiseNotification=this.raiseNotification.bind(this);
} }
componentDidMount() { componentDidMount() {
@ -59,14 +58,10 @@ class APStatus extends Component {
simpleGet( simpleGet(
AP_STATUS_ENDPOINT, AP_STATUS_ENDPOINT,
this.setState, this.setState,
this.raiseNotification this.props.raiseNotification
); );
} }
raiseNotification(errorMessage) {
this.snackbarNotification(errorMessage);
}
apStatusHighlight(status){ apStatusHighlight(status){
return status.active ? Highlight.SUCCESS : Highlight.IDLE; return status.active ? Highlight.SUCCESS : Highlight.IDLE;
} }
@ -136,7 +131,6 @@ class APStatus extends Component {
return ( return (
<SectionContent title="AP Status"> <SectionContent title="AP Status">
<SnackbarNotification notificationRef={(snackbarNotification)=>this.snackbarNotification = snackbarNotification} />
{ {
!fetched ? !fetched ?
<div> <div>
@ -162,4 +156,4 @@ class APStatus extends Component {
} }
} }
export default withStyles(styles)(APStatus); export default withNotifier(withStyles(styles)(APStatus));

View File

@ -1,8 +1,8 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { NTP_SETTINGS_ENDPOINT } from '../constants/Endpoints'; import { NTP_SETTINGS_ENDPOINT } from '../constants/Endpoints';
import {withNotifier} from '../components/SnackbarNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import SnackbarNotification from '../components/SnackbarNotification';
import NTPSettingsForm from '../forms/NTPSettingsForm'; import NTPSettingsForm from '../forms/NTPSettingsForm';
import { simpleGet } from '../helpers/SimpleGet'; import { simpleGet } from '../helpers/SimpleGet';
import { simplePost } from '../helpers/SimplePost'; import { simplePost } from '../helpers/SimplePost';
@ -31,7 +31,7 @@ class NTPSettings extends Component {
simpleGet( simpleGet(
NTP_SETTINGS_ENDPOINT, NTP_SETTINGS_ENDPOINT,
this.setState, this.setState,
this.raiseNotification, this.props.raiseNotification,
"ntpSettings", "ntpSettings",
"ntpSettingsFetched" "ntpSettingsFetched"
); );
@ -42,7 +42,7 @@ class NTPSettings extends Component {
NTP_SETTINGS_ENDPOINT, NTP_SETTINGS_ENDPOINT,
this.state, this.state,
this.setState, this.setState,
this.raiseNotification, this.props.raiseNotification,
"ntpSettings", "ntpSettings",
"ntpSettingsFetched" "ntpSettingsFetched"
); );
@ -58,7 +58,6 @@ class NTPSettings extends Component {
const { ntpSettingsFetched, ntpSettings, errorMessage } = this.state; const { ntpSettingsFetched, ntpSettings, errorMessage } = this.state;
return ( return (
<SectionContent title="NTP Settings"> <SectionContent title="NTP Settings">
<SnackbarNotification notificationRef={(raiseNotification)=>this.raiseNotification = raiseNotification} />
<NTPSettingsForm ntpSettingsFetched={ntpSettingsFetched} ntpSettings={ntpSettings} errorMessage={errorMessage} <NTPSettingsForm ntpSettingsFetched={ntpSettingsFetched} ntpSettings={ntpSettings} errorMessage={errorMessage}
onSubmit={this.saveNTPSettings} onReset={this.loadNTPSettings} handleValueChange={this.ntpSettingValueChange} /> onSubmit={this.saveNTPSettings} onReset={this.loadNTPSettings} handleValueChange={this.ntpSettingValueChange} />
</SectionContent> </SectionContent>
@ -67,4 +66,4 @@ class NTPSettings extends Component {
} }
export default NTPSettings; export default withNotifier(NTPSettings);

View File

@ -19,7 +19,7 @@ import * as Highlight from '../constants/Highlight';
import { unixTimeToTimeAndDate } from '../constants/TimeFormat'; import { unixTimeToTimeAndDate } from '../constants/TimeFormat';
import { NTP_STATUS_ENDPOINT } from '../constants/Endpoints'; import { NTP_STATUS_ENDPOINT } from '../constants/Endpoints';
import SnackbarNotification from '../components/SnackbarNotification'; import {withNotifier} from '../components/SnackbarNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import { simpleGet } from '../helpers/SimpleGet'; import { simpleGet } from '../helpers/SimpleGet';
@ -59,7 +59,6 @@ class NTPStatus extends Component {
this.setState = this.setState.bind(this); this.setState = this.setState.bind(this);
this.loadNTPStatus = this.loadNTPStatus.bind(this); this.loadNTPStatus = this.loadNTPStatus.bind(this);
this.raiseNotification=this.raiseNotification.bind(this);
} }
componentDidMount() { componentDidMount() {
@ -70,14 +69,10 @@ class NTPStatus extends Component {
simpleGet( simpleGet(
NTP_STATUS_ENDPOINT, NTP_STATUS_ENDPOINT,
this.setState, this.setState,
this.raiseNotification this.props.raiseNotification
); );
} }
raiseNotification(errorMessage) {
this.snackbarNotification(errorMessage);
}
renderNTPStatus(status, fullDetails, classes){ renderNTPStatus(status, fullDetails, classes){
const listItems = []; const listItems = [];
@ -160,7 +155,6 @@ class NTPStatus extends Component {
return ( return (
<SectionContent title="NTP Status"> <SectionContent title="NTP Status">
<SnackbarNotification notificationRef={(snackbarNotification)=>this.snackbarNotification = snackbarNotification} />
{ {
!fetched ? !fetched ?
<div> <div>
@ -186,4 +180,4 @@ class NTPStatus extends Component {
} }
} }
export default withStyles(styles)(NTPStatus); export default withNotifier(withStyles(styles)(NTPStatus));

View File

@ -1,8 +1,8 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { OTA_SETTINGS_ENDPOINT } from '../constants/Endpoints'; import { OTA_SETTINGS_ENDPOINT } from '../constants/Endpoints';
import {withNotifier} from '../components/SnackbarNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import SnackbarNotification from '../components/SnackbarNotification';
import OTASettingsForm from '../forms/OTASettingsForm'; import OTASettingsForm from '../forms/OTASettingsForm';
import { simpleGet } from '../helpers/SimpleGet'; import { simpleGet } from '../helpers/SimpleGet';
import { simplePost } from '../helpers/SimplePost'; import { simplePost } from '../helpers/SimplePost';
@ -31,7 +31,7 @@ class OTASettings extends Component {
simpleGet( simpleGet(
OTA_SETTINGS_ENDPOINT, OTA_SETTINGS_ENDPOINT,
this.setState, this.setState,
this.raiseNotification, this.props.raiseNotification,
"otaSettings", "otaSettings",
"otaSettingsFetched" "otaSettingsFetched"
); );
@ -42,7 +42,7 @@ class OTASettings extends Component {
OTA_SETTINGS_ENDPOINT, OTA_SETTINGS_ENDPOINT,
this.state, this.state,
this.setState, this.setState,
this.raiseNotification, this.props.raiseNotification,
"otaSettings", "otaSettings",
"otaSettingsFetched" "otaSettingsFetched"
); );
@ -64,7 +64,6 @@ class OTASettings extends Component {
const { otaSettingsFetched, otaSettings, errorMessage } = this.state; const { otaSettingsFetched, otaSettings, errorMessage } = this.state;
return ( return (
<SectionContent title="OTA Settings"> <SectionContent title="OTA Settings">
<SnackbarNotification notificationRef={(raiseNotification)=>this.raiseNotification = raiseNotification} />
<OTASettingsForm otaSettingsFetched={otaSettingsFetched} otaSettings={otaSettings} errorMessage={errorMessage} <OTASettingsForm otaSettingsFetched={otaSettingsFetched} otaSettings={otaSettings} errorMessage={errorMessage}
onSubmit={this.saveOTASettings} onReset={this.loadOTASettings} handleValueChange={this.otaSettingValueChange} onSubmit={this.saveOTASettings} onReset={this.loadOTASettings} handleValueChange={this.otaSettingValueChange}
handleCheckboxChange={this.otaSettingCheckboxChange} /> handleCheckboxChange={this.otaSettingCheckboxChange} />
@ -74,4 +73,4 @@ class OTASettings extends Component {
} }
export default OTASettings; export default withNotifier(OTASettings);

View File

@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import { SCAN_NETWORKS_ENDPOINT, LIST_NETWORKS_ENDPOINT } from '../constants/Endpoints'; import { SCAN_NETWORKS_ENDPOINT, LIST_NETWORKS_ENDPOINT } from '../constants/Endpoints';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import WiFiNetworkSelector from '../forms/WiFiNetworkSelector'; import WiFiNetworkSelector from '../forms/WiFiNetworkSelector';
import {withNotifier} from '../components/SnackbarNotification';
const NUM_POLLS = 10 const NUM_POLLS = 10
const POLLING_FREQUENCY = 500 const POLLING_FREQUENCY = 500
@ -44,6 +45,7 @@ class WiFiNetworkScanner extends Component {
} }
throw Error("Scanning for networks returned unexpected response code: " + response.status); throw Error("Scanning for networks returned unexpected response code: " + response.status);
}).catch(error => { }).catch(error => {
this.props.raiseNotification("Problem scanning: " + error.message);
this.setState({scanningForNetworks:false, networkList: null, errorMessage:error.message}); this.setState({scanningForNetworks:false, networkList: null, errorMessage:error.message});
}); });
} }
@ -78,7 +80,7 @@ class WiFiNetworkScanner extends Component {
this.schedulePollTimeout(); this.schedulePollTimeout();
throw this.retryError(); throw this.retryError();
}else{ }else{
throw Error("Device did not return network list in timley manner."); throw Error("Device did not return network list in timely manner.");
} }
} }
throw Error("Device returned unexpected response code: " + response.status); throw Error("Device returned unexpected response code: " + response.status);
@ -90,6 +92,7 @@ class WiFiNetworkScanner extends Component {
.catch(error => { .catch(error => {
console.log(error.message); console.log(error.message);
if (error.name !== RETRY_EXCEPTION_TYPE) { if (error.name !== RETRY_EXCEPTION_TYPE) {
this.props.raiseNotification("Problem scanning: " + error.message);
this.setState({scanningForNetworks:false, networkList: null, errorMessage:error.message}); this.setState({scanningForNetworks:false, networkList: null, errorMessage:error.message});
} }
}); });
@ -115,4 +118,4 @@ WiFiNetworkScanner.propTypes = {
selectNetwork: PropTypes.func.isRequired selectNetwork: PropTypes.func.isRequired
}; };
export default (WiFiNetworkScanner); export default withNotifier(WiFiNetworkScanner);

View File

@ -2,8 +2,8 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { WIFI_SETTINGS_ENDPOINT } from '../constants/Endpoints'; import { WIFI_SETTINGS_ENDPOINT } from '../constants/Endpoints';
import {withNotifier} from '../components/SnackbarNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import SnackbarNotification from '../components/SnackbarNotification';
import WiFiSettingsForm from '../forms/WiFiSettingsForm'; import WiFiSettingsForm from '../forms/WiFiSettingsForm';
import { simpleGet } from '../helpers/SimpleGet'; import { simpleGet } from '../helpers/SimpleGet';
import { simplePost } from '../helpers/SimplePost'; import { simplePost } from '../helpers/SimplePost';
@ -48,7 +48,7 @@ class WiFiSettings extends Component {
simpleGet( simpleGet(
WIFI_SETTINGS_ENDPOINT, WIFI_SETTINGS_ENDPOINT,
this.setState, this.setState,
this.raiseNotification, this.props.raiseNotification,
"wifiSettings", "wifiSettings",
"wifiSettingsFetched" "wifiSettingsFetched"
); );
@ -59,7 +59,7 @@ class WiFiSettings extends Component {
WIFI_SETTINGS_ENDPOINT, WIFI_SETTINGS_ENDPOINT,
this.state, this.state,
this.setState, this.setState,
this.raiseNotification, this.props.raiseNotification,
"wifiSettings", "wifiSettings",
"wifiSettingsFetched" "wifiSettingsFetched"
); );
@ -85,7 +85,6 @@ class WiFiSettings extends Component {
const { wifiSettingsFetched, wifiSettings, errorMessage, selectedNetwork } = this.state; const { wifiSettingsFetched, wifiSettings, errorMessage, selectedNetwork } = this.state;
return ( return (
<SectionContent title="WiFi Settings"> <SectionContent title="WiFi Settings">
<SnackbarNotification notificationRef={(raiseNotification)=>this.raiseNotification = raiseNotification} />
<WiFiSettingsForm wifiSettingsFetched={wifiSettingsFetched} wifiSettings={wifiSettings} errorMessage={errorMessage} selectedNetwork={selectedNetwork} deselectNetwork={this.deselectNetwork} <WiFiSettingsForm wifiSettingsFetched={wifiSettingsFetched} wifiSettings={wifiSettings} errorMessage={errorMessage} selectedNetwork={selectedNetwork} deselectNetwork={this.deselectNetwork}
onSubmit={this.saveWiFiSettings} onReset={this.loadWiFiSettings} handleValueChange={this.wifiSettingValueChange} handleCheckboxChange={this.wifiSettingCheckboxChange} /> onSubmit={this.saveWiFiSettings} onReset={this.loadWiFiSettings} handleValueChange={this.wifiSettingValueChange} handleCheckboxChange={this.wifiSettingCheckboxChange} />
</SectionContent> </SectionContent>
@ -99,4 +98,4 @@ WiFiSettings.propTypes = {
selectedNetwork: PropTypes.object selectedNetwork: PropTypes.object
}; };
export default WiFiSettings; export default withNotifier(WiFiSettings);

View File

@ -5,7 +5,7 @@ import Button from 'material-ui/Button';
import { LinearProgress } from 'material-ui/Progress'; import { LinearProgress } from 'material-ui/Progress';
import Typography from 'material-ui/Typography'; import Typography from 'material-ui/Typography';
import SnackbarNotification from '../components/SnackbarNotification'; import {withNotifier} from '../components/SnackbarNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import { WIFI_STATUS_ENDPOINT } from '../constants/Endpoints'; import { WIFI_STATUS_ENDPOINT } from '../constants/Endpoints';
@ -75,7 +75,7 @@ class WiFiStatus extends Component {
simpleGet( simpleGet(
WIFI_STATUS_ENDPOINT, WIFI_STATUS_ENDPOINT,
this.setState, this.setState,
this.raiseNotification this.props.raiseNotification
); );
} }
@ -159,7 +159,6 @@ class WiFiStatus extends Component {
return ( return (
<SectionContent title="WiFi Status"> <SectionContent title="WiFi Status">
<SnackbarNotification notificationRef={(raiseNotification)=>this.raiseNotification = raiseNotification} />
{ {
!fetched ? !fetched ?
<div> <div>
@ -185,4 +184,4 @@ class WiFiStatus extends Component {
} }
} }
export default withStyles(styles)(WiFiStatus); export default withNotifier(withStyles(styles)(WiFiStatus));

View File

@ -28,7 +28,7 @@ export const simpleGet = (
.then(json => {setState({[dataKey]: json, [fetchedKey]:true})}) .then(json => {setState({[dataKey]: json, [fetchedKey]:true})})
.catch(error =>{ .catch(error =>{
if (raiseNotification) { if (raiseNotification) {
raiseNotification("Problem fetching. " + error.message); raiseNotification("Problem fetching: " + error.message);
} }
setState({[dataKey]: null, [fetchedKey]:true, [errorMessageKey]:error.message}); setState({[dataKey]: null, [fetchedKey]:true, [errorMessageKey]:error.message});
}); });

View File

@ -32,7 +32,7 @@ export const simplePost = (
raiseNotification("Changes successfully applied."); raiseNotification("Changes successfully applied.");
setState({[dataKey]: json, [fetchedKey]:true}); setState({[dataKey]: json, [fetchedKey]:true});
}).catch(error => { }).catch(error => {
raiseNotification("Problem saving. " + error.message); raiseNotification("Problem saving: " + error.message);
setState({[dataKey]: null, [fetchedKey]:true, [errorMessageKey]:error.message}); setState({[dataKey]: null, [fetchedKey]:true, [errorMessageKey]:error.message});
}); });
} }