From c594888953151ddfb4ca04b7752bfd51edc1d6da Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 13 Feb 2019 01:11:31 -0500 Subject: WIP: migrate to TypeScriptX --- src/Analyze.tsx | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 src/Analyze.tsx (limited to 'src/Analyze.tsx') diff --git a/src/Analyze.tsx b/src/Analyze.tsx new file mode 100644 index 0000000..5450998 --- /dev/null +++ b/src/Analyze.tsx @@ -0,0 +1,270 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import 'react-dates/initialize'; +import 'react-dates/lib/css/_datepicker.css'; +import { DateRangePicker } from 'react-dates'; +import { Theme, withStyles } from '@material-ui/core/styles'; +import cyan from '@material-ui/core/colors/cyan'; +import deepOrange from '@material-ui/core/colors/deepOrange'; +import CssBaseline from '@material-ui/core/CssBaseline'; +import Typography from '@material-ui/core/Typography'; +import Button from '@material-ui/core/Button'; +import FormControl from '@material-ui/core/FormControl'; +import FormGroup from '@material-ui/core/FormGroup'; +import Grid from '@material-ui/core/Grid'; +import AddCircleIcon from '@material-ui/icons/AddCircle'; +import IconButton from '@material-ui/core/IconButton'; +import * as gapi from './gapi'; +import { MsgType, MsgClient } from './msg'; +import { Pattern, PatternEntry } from './pattern'; +import { AnalyzePieChart, getChartData } from './Chart'; +import PatternTable from './PatternTable'; +import Snackbar from './Snackbar'; +import AlertDialog from './Dialog'; +import moment from 'moment'; + +const default_chart_data = [ + {name: 'Work', value: 10, color: cyan[300]}, + {name: 'Wasted', value: 10, color: deepOrange[300]}]; + +const styles = (theme: Theme) => ({ + buttonSpacer: { + marginBottom: theme.spacing.unit * 4, + }, +}); + +class Analyze extends React.Component { + msgClient: MsgClient; + + state = { + patterns: [] as PatternEntry[], + calendars: {}, + startDate: null as moment.Moment, + endDate: null as moment.Moment, + patternGraphData: default_chart_data, + calendarGraphData: default_chart_data, + snackBarOpen: false, + snackBarMsg: 'unknown', + snackBarVariant: 'error', + dialogOpen: false, + dialogMsg: {title: '', message: ''} + }; + + constructor(props: any) { + super(props); + + this.msgClient = new MsgClient('main'); + + this.msgClient.sendMsg({ + type: MsgType.getPatterns, + data: { id: 'analyze' } + }).then(msg => { + this.setState({ patterns: msg.data.map(p => PatternEntry.inflate(p)) }); + }); + + 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')); + + this.dialogPromiseResolver = null; + } + + loadPatterns = (patterns: PatternEntry[]) => { + this.msgClient.sendMsg({ + type: MsgType.updatePatterns, + data: { id: 'analyze', patterns: patterns.map(p => p.deflate()) } + }).then(() => this.setState({ patterns })); + }; + + updatePattern = (field: string, idx: number, value: PatternEntry[]) => { + let patterns = this.state.patterns; + patterns[idx][field] = value; + this.loadPatterns(patterns); + }; + + removePattern = (idx: number) => { + let patterns = this.state.patterns; + patterns.splice(idx, 1); + for (let i = 0; i < patterns.length; i++) + patterns[i].idx = i; + this.loadPatterns(patterns); + }; + + newPattern = () => { + let patterns = [PatternEntry.defaultPatternEntry(0), ...this.state.patterns]; + for (let i = 1; i < patterns.length; i++) + patterns[i].idx = i; + this.loadPatterns(patterns); + }; + + getCalEvents = (id: string, start: Date, end: Date) => { + return this.msgClient.sendMsg({ type: MsgType.getCalEvents, data: { id, + start: start.getTime(), + end: end.getTime() } }) + .then(({ data }) => data.map(e => { + return { + id: e.id, + start: new Date(e.start), + end: new Date(e.end) } + })); + } + + analyze = () => { + if (!(this.state.startDate && this.state.endDate)) { + this.handleSnackbarOpen('Please choose a valid time range.', 'error'); + return; + } + let start = this.state.startDate.startOf('day').toDate(); + let end = this.state.endDate.startOf('day').toDate(); + getChartData(start, end, + this.state.patterns, + this.state.calendars, + this.getCalEvents).then(results => { + this.setState(results); + }); + } + + reset = () => { + this.handleDialogOpen("Reset", "Are you sure to reset the patterns?").then(ans => { + if (!ans) return; + this.loadPatterns([]); + this.setState({ startDate: null, endDate: null }); + }); + } + + loadDefaultPatterns() { + let patterns = []; + let idx = 0; + for (let id in this.state.calendars) { + let cal = this.state.calendars[id]; + if (!cal.enabled) continue; + patterns.push(new PatternEntry(cal.name, idx++, + new Pattern(id, false, cal.name, cal.name), + Pattern.anyPattern(), + cal.color)); + } + console.log(patterns); + this.loadPatterns(patterns); + } + + default = () => { + this.handleDialogOpen("Load Default", "Load the calendars as patterns?").then(ans => { + if (!ans) return; + this.loadDefaultPatterns(); + }); + } + + handleSnackbarClose = (event, reason) => { + if (reason === 'clickaway') return; + this.setState({ snackBarOpen: false }); + } + + handleSnackbarOpen = (msg, variant) => { + this.setState({ snackBarOpen: true, snackBarMsg: msg, snackBarVariant: variant }); + } + + 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 ( + + + + + + + + Analyzed Events + this.newPattern()}> + + + + + + Time Range + +
+ { + this.setState({ startDate, endDate }); + }} + focusedInput={this.state.focusedInput} + onFocusChange={focusedInput => this.setState({ focusedInput })} + isOutsideRange={() => false} /> +
+
+
+ + + + + + + + + + + + + + + + + + + + + + Results + + + + + ); + } +} + +Analyze.propTypes = { + classes: PropTypes.object.isRequired, +}; + +export default withStyles(styles)(Analyze); -- cgit v1.2.3