diff --git a/src/components/AppHeader/AccountMenu.jsx b/src/components/AppHeader/AccountMenu.jsx new file mode 100644 index 00000000..447714cc --- /dev/null +++ b/src/components/AppHeader/AccountMenu.jsx @@ -0,0 +1,71 @@ +import React, { useCallback, useEffect, useState } from 'react'; +import dayjs from 'dayjs'; + +import { + Divider, + ListItem, + Menu, + MenuItem, +} from '@material-ui/core'; + +import MyCommaAuth from '@commaai/my-comma-auth'; + +const logOut = async () => { + await MyCommaAuth.logOut(); + if (window.location) { + window.location = window.location.origin; + } +}; + +const AccountMenu = ({ profile, open, anchorEl, onClose, ...rest }) => { + const [buildTimestamp, setBuildTimestamp] = useState(''); + const [version, setVersion] = useState(''); + + useEffect(() => { + setVersion(import.meta.env.VITE_APP_GIT_SHA?.substring(0, 7) || 'dev'); + + const buildDate = import.meta.env.VITE_APP_BUILD_TIMESTAMP; + if (buildDate) { + setBuildTimestamp(`, ${dayjs(buildDate).fromNow()}`); + } + }, []); + + const onLogOut = useCallback(() => { + onClose(); + logOut(); + }, [onClose]); + + return ( + + + {profile.email} + { profile.user_id } + {`Version: ${version}${buildTimestamp}`} + + + + Manage Account + + + Log out + + + ); +}; + +export default AccountMenu; diff --git a/src/components/AppHeader/index.jsx b/src/components/AppHeader/index.jsx index 28303f50..6206d8b0 100644 --- a/src/components/AppHeader/index.jsx +++ b/src/components/AppHeader/index.jsx @@ -1,20 +1,21 @@ -import React, { Component } from 'react'; +import React, { useCallback, useState } from 'react'; import { connect } from 'react-redux'; import Obstruction from 'obstruction'; -import dayjs from 'dayjs'; import { withStyles } from '@material-ui/core/styles'; -import { Divider, Typography, Menu, MenuItem, ListItem, IconButton, Icon, AppBar } from '@material-ui/core'; +import { Typography, IconButton, Icon, AppBar } from '@material-ui/core'; import MyCommaAuth from '@commaai/my-comma-auth'; import { selectDevice } from '../../actions'; -import TimeFilter from './TimeFilter'; import { AccountIcon } from '../../icons'; import Colors from '../../colors'; import ResizeHandler from '../ResizeHandler'; import { filterRegularClick } from '../../utils'; +import AccountMenu from './AccountMenu'; +import TimeFilter from './TimeFilter'; + const styles = () => ({ header: { backgroundColor: '#1D2225', @@ -31,9 +32,6 @@ const styles = () => ({ alignItems: 'center', flexWrap: 'nowrap', }, - hamburger: { - marginRight: 10, - }, logo: { alignItems: 'center', display: 'flex', @@ -57,169 +55,103 @@ const styles = () => ({ height: 34, width: 34, }, - accountListItem: { - color: Colors.white, - padding: '12px 16px', - }, - accountListEmail: { - flexDirection: 'column', - alignItems: 'flex-start', - '& :first-child': { - fontWeight: 'bold', - }, - '& :not(:first-child)': { - fontSize: '0.75em', - color: Colors.white40, - paddingTop: 8, - }, - }, - accountMenuItem: { - padding: '12px 16px', - }, }); -class AppHeader extends Component { - constructor(props) { - super(props); - - this.handleClickedAccount = this.handleClickedAccount.bind(this); - this.handleClose = this.handleClose.bind(this); - this.handleLogOut = this.handleLogOut.bind(this); - this.toggleDrawer = this.toggleDrawer.bind(this); - this.onResize = this.onResize.bind(this); +const AppHeader = ({ + profile, classes, dispatch, drawerIsOpen, annotating, showDrawerButton, + forwardRef, clips, handleDrawerStateChanged, primeNav, dongleId, +}) => { + const [anchorEl, setAnchorEl] = useState(null); + const [windowWidth, setWindowWidth] = useState(window.innerWidth); - this.state = { - anchorEl: null, - windowWidth: window.innerWidth, - }; - } - - toggleDrawer() { - this.props.handleDrawerStateChanged(!this.props.drawerIsOpen); - } - - handleClickedAccount(event) { + const handleClickedAccount = useCallback((event) => { if (MyCommaAuth.isAuthenticated()) { - this.setState({ anchorEl: event.currentTarget }); + setAnchorEl(event.currentTarget); } else if (window.location) { window.location = window.location.origin; } - } + }, []); - handleClose() { - this.setState({ anchorEl: null }); - } + const handleClose = useCallback(() => { + setAnchorEl(null); + }, []); - async handleLogOut() { - this.handleClose(); - await MyCommaAuth.logOut(); + const toggleDrawer = useCallback(() => { + dispatch(handleDrawerStateChanged(!drawerIsOpen)); + }, [dispatch, drawerIsOpen, handleDrawerStateChanged]); - if (window.location) { - window.location = window.location.origin; - } - } + const onResize = useCallback((width) => { + setWindowWidth(width); + }, []); - onResize(windowWidth) { - this.setState({ windowWidth }); - } + const open = Boolean(anchorEl); - render() { - const { profile, classes, dispatch, annotating, forwardRef, showDrawerButton, primeNav, clips, dongleId } = this.props; - const { anchorEl, windowWidth } = this.state; - const open = Boolean(anchorEl); - - let reorderWideStyle = {}; - if (windowWidth < 640) { - reorderWideStyle = { - order: 4, - width: '100%', - display: 'flex', - justifyContent: 'center', - }; - } + let reorderWideStyle = {}; + if (windowWidth < 640) { + reorderWideStyle = { + order: 4, + width: '100%', + display: 'flex', + justifyContent: 'center', + }; + } - const version = import.meta.env.VITE_APP_GIT_SHA?.substring(0, 7) || 'dev'; - const buildDate = import.meta.env.VITE_APP_BUILD_TIMESTAMP; - let buildTimestamp = '' - if (buildDate) { - buildTimestamp = `, ${dayjs(buildDate).fromNow()}`; - } - return ( - <> - - -
-
- { showDrawerButton ? ( - - menu - - ) - : ( - dispatch(selectDevice(dongleId))) } - > - comma - - )} - dispatch(selectDevice(dongleId))) } + return ( + <> + + +
+ -
- { Boolean(!primeNav && !clips && !annotating && dongleId) && } -
- menu + + ) + : ( + dispatch(selectDevice(dongleId)))} + > + comma + + )} + dispatch(selectDevice(dongleId)))} > - - + connect +
- - { Boolean(MyCommaAuth.isAuthenticated() && profile) && ( - + {Boolean(!primeNav && !clips && !annotating && dongleId) && } +
+ + + +
+
+ {Boolean(MyCommaAuth.isAuthenticated() && profile) && ( + - - { profile.email } - { profile.user_id } - {`Version: ${version}${buildTimestamp}`} - - - - Manage Account - - - Log out - - - ) } - - ); - } -} + onClose={handleClose} + profile={profile} + /> + )} + + ); +}; const stateToProps = Obstruction({ dongleId: 'dongleId', diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index 14726b56..d82c1850 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -3,7 +3,6 @@ import { connect } from 'react-redux'; import Obstruction from 'obstruction'; import localforage from 'localforage'; import { replace } from 'connected-react-router'; -import * as Sentry from '@sentry/react'; import { withStyles, Button, CircularProgress, Divider, Grid, Modal, Paper, Typography } from '@material-ui/core'; import 'mapbox-gl/src/css/mapbox-gl.css'; @@ -19,8 +18,9 @@ import PullDownReload from './utils/PullDownReload'; import { analyticsEvent, selectDevice, updateDevice } from '../actions'; import init from '../actions/startup'; import Colors from '../colors'; -import { verifyPairToken, pairErrorToMessage } from '../utils'; import { play, pause } from '../timeline/playback'; +import { verifyPairToken, pairErrorToMessage } from '../utils'; + import ResizeHandler from './ResizeHandler'; const ClipView = lazy(() => import('./ClipView')); diff --git a/tailwind.config.js b/tailwind.config.js index d463cdb7..7b9194ab 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,5 +1,6 @@ /** @type {import('tailwindcss').Config} */ module.exports = { + important: true, content: [ './index.html', './src/**/*.{js,ts,jsx,tsx}',