From d88b873c63d8ad5b5336b509f8a4ee35a583e279 Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 6 Feb 2019 21:13:23 -0500 Subject: add snackbar and dialog --- src/CustomAnalyzer.js | 20 +++++++++++++ src/Dialog.js | 45 +++++++++++++++++++++++++++++ src/Settings.js | 53 ++++++++++++++++++++++++++++++---- src/Snackbar.js | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/gapi.js | 4 +-- 5 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 src/Dialog.js create mode 100644 src/Snackbar.js (limited to 'src') diff --git a/src/CustomAnalyzer.js b/src/CustomAnalyzer.js index f140151..62a8e39 100644 --- a/src/CustomAnalyzer.js +++ b/src/CustomAnalyzer.js @@ -18,6 +18,7 @@ import { msgType, MsgClient } from './msg'; import { Pattern, PatternEntry } from './pattern'; import PieChart from './Chart'; import PatternTable from './PatternTable'; +import Snackbar from './Snackbar'; const default_chart_data = [ {name: 'Work', value: 10, color: cyan[300]}, @@ -43,6 +44,9 @@ class CustomAnalyzer extends React.Component { endDate: null, patternGraphData: default_chart_data, calendarGraphData: default_chart_data, + snackBarOpen: false, + snackBarMsg: 'unknown', + snackBarVariant: 'error' }; constructor(props) { @@ -57,6 +61,8 @@ class CustomAnalyzer extends React.Component { this.msgClient.sendMsg({ type: msgType.getCalendars, data: { enabledOnly: true }}).then(msg => { this.setState({ calendars: msg.data }); }); + gapi.getLoggedIn().then(b => !b && + this.handleSnackbarOpen('Not logged in. Operating in offline mode.', 'warning')); } updatePattern = (field, idx, value) => { @@ -171,11 +177,25 @@ class CustomAnalyzer extends React.Component { this.setState({ startDate: null, endDate: null }); } + handleSnackbarClose = (event, reason) => { + if (reason === 'clickaway') return; + this.setState({ snackBarOpen: false }); + } + + handleSnackbarOpen = (msg, variant) => { + this.setState({ snackBarOpen: true, snackBarMsg: msg, snackBarVariant: variant }); + } + render() { const { classes } = this.props; return ( + diff --git a/src/Dialog.js b/src/Dialog.js new file mode 100644 index 0000000..7e24176 --- /dev/null +++ b/src/Dialog.js @@ -0,0 +1,45 @@ +import React from 'react'; +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import Button from '@material-ui/core/Button'; +import Slide from '@material-ui/core/Slide'; + +// modified from https://material-ui.com/demos/dialogs/ + +function Transition(props) { + return ; +} + +function AlertDialog(props) { + return ( + props.handleClose(false)} + aria-labelledby="alert-dialog-slide-title" + aria-describedby="alert-dialog-slide-description"> + + {props.title} + + + + {props.message} + + + + + + + + ); +} + +export default AlertDialog; diff --git a/src/Settings.js b/src/Settings.js index e071f9e..3865438 100644 --- a/src/Settings.js +++ b/src/Settings.js @@ -23,6 +23,8 @@ import * as gapi from './gapi'; import { msgType, MsgClient } from './msg'; import { Pattern, PatternEntry } from './pattern'; import PatternTable from './PatternTable'; +import Snackbar from './Snackbar'; +import AlertDialog from './Dialog'; const styles = theme => ({ tableHead: { @@ -32,6 +34,7 @@ const styles = theme => ({ }, tableContent: { textAlign: 'left', + maxWidth: 600, }, calendarList: { maxHeight: 400, @@ -57,6 +60,10 @@ class Settings extends React.Component { isLoggedIn: false, patterns: [], calendars: {}, + snackBarOpen: false, + snackBarMsg: 'unknown', + dialogOpen: false, + dialogMsg: {title: '', message: ''}, }; constructor(props) { @@ -72,19 +79,23 @@ class Settings extends React.Component { this.msgClient.sendMsg({ type: msgType.getCalendars, data: { enabledOnly: false } }).then(msg => { this.setState({ calendars: msg.data }); }); + this.dialogPromiseResolver = null; } handleLogin = () => { gapi.login().then(() => { this.setState({ isLoggedIn: true }); this.loadAll(true); - }); + }).catch(() => this.handleSnackbarOpen("Failed to login!")); } handleLogout = () => { - gapi.logout().then(() => { - this.setState({ isLoggedIn: false }); - this.loadPatterns([], 'analyze'); + this.handleDialogOpen("Logout", "Are you sure to logout?").then(ans => { + if (!ans) return; + gapi.logout().then(() => { + this.setState({ isLoggedIn: false }); + //this.loadPatterns([], 'analyze'); + }).catch(() => this.handleSnackbarOpen("Failed to logout!")); }); } @@ -167,10 +178,42 @@ class Settings extends React.Component { }).then(() => this.setState({ patterns })); }; + handleSnackbarClose = (event, reason) => { + if (reason === 'clickaway') return; + this.setState({ snackBarOpen: false }); + } + + handleSnackbarOpen = msg => { + this.setState({ snackBarOpen: true, snackBarMsg: msg }); + } + + handleDialogOpen = (title, message) => { + let pm = new Promise(resolver => { + this.dialogPromiseResolver = resolver + }); + this.setState({ dialogOpen: true, dialogMsg: {title, message} }); + return pm; + } + + handleDialogClose = result => { + this.dialogPromiseResolver(result); + this.setState({ dialogOpen: false }); + } + render() { const { classes } = this.props; return (
+ + General @@ -178,7 +221,7 @@ class Settings extends React.Component { Account - + { (this.state.isLoggedIn && ) || diff --git a/src/Snackbar.js b/src/Snackbar.js new file mode 100644 index 0000000..f17863c --- /dev/null +++ b/src/Snackbar.js @@ -0,0 +1,78 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { withStyles } from '@material-ui/core/styles'; +import amber from '@material-ui/core/colors/amber'; +import Snackbar from '@material-ui/core/Snackbar'; +import SnackbarContent from '@material-ui/core/SnackbarContent'; +import ErrorIcon from '@material-ui/icons/Error'; +import WarningIcon from '@material-ui/icons/Warning'; +import CloseIcon from '@material-ui/icons/Close'; +import IconButton from '@material-ui/core/IconButton'; + +// modified from https://material-ui.com/demos/snackbars/ + +const variantIcon = { + error: ErrorIcon, + warning: WarningIcon, +}; + +const styles = theme => ({ + error: { + backgroundColor: theme.palette.error.dark, + }, + warning: { + backgroundColor: amber[700], + }, + icon: { + fontSize: 20, + }, + iconVariant: { + opacity: 0.9, + marginRight: theme.spacing.unit, + }, + message: { + display: 'flex', + alignItems: 'center', + }, +}); + +function CustomSnackbar(props) { + const { classes, className, message, variant, open, onClose, ...other } = props; + const Icon = variantIcon[variant]; + return ( + + + + {message} + + } + action={[ + + + , + ]} + {...other} + /> + + ); +} + +export default withStyles(styles)(CustomSnackbar); diff --git a/src/gapi.js b/src/gapi.js index 60e9b1a..36af906 100644 --- a/src/gapi.js +++ b/src/gapi.js @@ -34,8 +34,8 @@ export function getLoggedIn() { if (loggedIn === null) { return _getAuthToken(false) - .then(() => {loggedIn = true}) - .catch(() => {loggedIn = false; console.log("here");}) + .then(() => loggedIn = true) + .catch(() => loggedIn = false) .then(() => loggedIn); } else return Promise.resolve(loggedIn); -- cgit v1.2.3