import React from 'react'; import PropTypes from 'prop-types'; import 'typeface-roboto'; import 'react-dates/initialize'; import 'react-dates/lib/css/_datepicker.css'; import { DateRangePicker } from 'react-dates'; import { withStyles } from '@material-ui/core/styles'; import { MuiThemeProvider } from '@material-ui/core/styles'; import cyan from '@material-ui/core/colors/cyan'; import CssBaseline from '@material-ui/core/CssBaseline'; import AppBar from '@material-ui/core/AppBar'; import Toolbar from '@material-ui/core/Toolbar'; 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 Logo from './Logo'; import * as gapi from './gapi'; import { Pattern, PatternEntry } from './pattern'; import PieChart from './Chart'; import PatternTable from './PatternTable'; import theme from './theme'; const default_chart_data = [ {name: 'Work', value: 10, color: cyan[300]}, {name: 'Wasted', value: 10, color: cyan[300]}]; function filterPatterns(patterns, calName) { return patterns.filter(p => { return p.cal.regex.test(calName); }); } const styles = theme => ({ root: { display: 'flex', height: '100vh', }, appBar: { zIndex: theme.zIndex.drawer + 1, transition: theme.transitions.create(['width', 'margin'], { easing: theme.transitions.easing.sharp, duration: theme.transitions.duration.leavingScreen, }), }, title: { flexGrow: 1, }, sectionTitle: { flex: '0 0 auto' }, appBarSpacer: theme.mixins.toolbar, content: { flexGrow: 1, padding: theme.spacing.unit * 3, overflow: 'auto', }, buttonSpacer: { marginBottom: theme.spacing.unit * 4, }, fab: { margin: theme.spacing.unit, }, }); class Dashboard extends React.Component { state = { patterns: [], timeRange: null, token: gapi.getAuthToken(), patternGraphData: default_chart_data, calendarGraphData: default_chart_data, activePattern: null }; cached = { calendars: {} }; handleChangePage = (event, page) => { this.setState({ page }); }; handleChangeRowsPerPage = event => { this.setState({ rowsPerPage: event.target.value }); }; updatePattern = (field, idx, value) => { let patterns = this.state.patterns; patterns[idx][field] = value; this.setState({ patterns }); }; removePattern = idx => { let patterns = this.state.patterns; patterns.splice(idx, 1); for (let i = 0; i < patterns.length; i++) patterns[i].idx = i; this.setState({ patterns }); }; newPattern = () => { let patterns = [PatternEntry.defaultPatternEntry(), ...this.state.patterns]; for (let i = 1; i < patterns.length; i++) patterns[i].idx = i; this.setState({ patterns }); }; analyze = () => { if (!(this.state.startDate && this.state.endDate)) { alert("Please choose a valid time range."); return; } let start = this.state.startDate.toISOString(); let end = this.state.endDate.toISOString(); let event_pms = []; for (let id in this.cached.calendars) { event_pms.push( this.state.token .then(gapi.genEventsGetter(id, start, end)) .then(items => this.cached.calendars[id].events = items)); } Promise.all(event_pms).then(() => { let results = {}; // pattern idx => time let cal_results = {}; // cal id => time for (let i = 0; i < this.state.patterns.length; i++) results[i] = 0; for (let id in this.cached.calendars) { let patterns = filterPatterns(this.state.patterns, this.cached.calendars[id].name); if (!this.cached.calendars[id].events) continue; this.cached.calendars[id].events.forEach(event => { if (event.status !== "confirmed") return; patterns.forEach(p => { if (!p.event.regex.test(event.summary)) return; if (cal_results[id] === undefined) { cal_results[id] = 0; } let duration = (new Date(event.end.dateTime) - new Date(event.start.dateTime)) / 60000; results[p.idx] += duration; cal_results[id] += duration; }); }); } let patternGraphData = []; let calendarGraphData = []; for (let i = 0; i < this.state.patterns.length; i++) { patternGraphData.push({ name: this.state.patterns[i].name, value: results[i] / 60.0 }); } for (let id in cal_results) { calendarGraphData.push({ name: this.cached.calendars[id].name, value: (cal_results[id] / 60.0), color: this.cached.calendars[id].color.background}); } this.setState({ patternGraphData, calendarGraphData }); }); }; loadPatterns = () => { let token = this.state.token; let colors = token.then(gapi.getColors).then(color => { return color.calendar; }); let cals = token.then(gapi.getCalendars); Promise.all([colors, cals]).then(([colors, items]) => { items.forEach(item => { this.cached.calendars[item.id] = { name: item.summary, events: {}, color: colors[item.colorId] }; }); this.setState({ patterns: items.map((item, idx) => { return new PatternEntry(item.summary, idx, new Pattern(item.id, false, item.summary, item.summary), Pattern.anyPattern()); })}); }); }; render() { const { classes } = this.props; return (
Chromicle
Event Patterns this.newPattern()}> Time Range
{ this.setState({ startDate, endDate }); }} focusedInput={this.state.focusedInput} onFocusChange={focusedInput => this.setState({ focusedInput })} isOutsideRange={() => false}/>
Graph
); } } Dashboard.propTypes = { classes: PropTypes.object.isRequired, }; export default withStyles(styles)(Dashboard);