Feat: make footer expand on hover

chore: rename status variable from showExpandBtn to canExpand

Chore: disable notific. card, redirect to dashboard on logo click

This commit also fixes eslint warnings about anonymous exports
On the header, the Dashboard link is removed, in favour of adding
a redirect on click on the Lamassu Admin text. "Machines" header
link is removed as well, and a machine profile can be accessed
through the dashboard -> System Status card
This commit is contained in:
Cesar 2020-11-30 14:06:44 +00:00 committed by Josh Harvey
parent 00f176fccc
commit 5572fb0eb1
16 changed files with 126 additions and 103 deletions

View file

@ -60,7 +60,9 @@ const Header = memo(({ tree }) => {
<header> <header>
<div className={classes.header}> <div className={classes.header}>
<div className={classes.content}> <div className={classes.content}>
<div className={classes.logo}> <div
onClick={() => history.push('/dashboard')}
className={classnames(classes.logo, classes.logoLink)}>
<Logo /> <Logo />
<H4 className={classes.white}>Lamassu Admin</H4> <H4 className={classes.white}>Lamassu Admin</H4>
</div> </div>

View file

@ -20,7 +20,7 @@ if (version === 8) {
subheaderHeight = spacer * 7 subheaderHeight = spacer * 7
} }
export default { const styles = {
header: { header: {
backgroundColor: primaryColor, backgroundColor: primaryColor,
color: white, color: white,
@ -164,5 +164,10 @@ export default {
'& > svg': { '& > svg': {
marginRight: 16 marginRight: 16
} }
},
logoLink: {
cursor: 'pointer'
} }
} }
export default styles

View file

@ -5,7 +5,7 @@ import {
primaryColor primaryColor
} from 'src/styling/variables' } from 'src/styling/variables'
export default { const styles = {
label: { label: {
margin: 0, margin: 0,
color: offColor color: offColor
@ -62,3 +62,4 @@ export default {
} }
} }
} }
export default styles

View file

@ -2,7 +2,7 @@ import typographyStyles from 'src/components/typography/styles'
import { spacer, white, primaryColor } from 'src/styling/variables' import { spacer, white, primaryColor } from 'src/styling/variables'
const { label1 } = typographyStyles const { label1 } = typographyStyles
export default { const styles = {
root: { root: {
flexGrow: 1, flexGrow: 1,
marginBottom: 108 marginBottom: 108
@ -60,3 +60,5 @@ export default {
} }
} }
} }
export default styles

View file

@ -1,15 +1,14 @@
import { useQuery } from '@apollo/react-hooks' import { useQuery } from '@apollo/react-hooks'
import { makeStyles } from '@material-ui/core' import { makeStyles } from '@material-ui/core'
import Button from '@material-ui/core/Button'
import Grid from '@material-ui/core/Grid' import Grid from '@material-ui/core/Grid'
import gql from 'graphql-tag' import gql from 'graphql-tag'
import * as R from 'ramda' import * as R from 'ramda'
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { Label1, Label2 } from 'src/components/typography' import { Label2 } from 'src/components/typography'
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg' import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg' import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
import { white } from 'src/styling/variables' import { white, spacer } from 'src/styling/variables'
import { fromNamespace } from 'src/utils/config' import { fromNamespace } from 'src/utils/config'
import styles from './Footer.styles' import styles from './Footer.styles'
@ -32,31 +31,19 @@ const useStyles = makeStyles(styles)
const Footer = () => { const Footer = () => {
const { data, loading } = useQuery(GET_DATA) const { data, loading } = useQuery(GET_DATA)
const [expanded, setExpanded] = useState(false) const [expanded, setExpanded] = useState(false)
const [showExpandBtn, setShowExpandBtn] = useState(false) const [canExpand, setCanExpand] = useState(false)
const [buttonName, setButtonName] = useState('Show all') const [delayedExpand, setDelayedExpand] = useState(null)
const classes = useStyles() const classes = useStyles()
useEffect(() => { useEffect(() => {
if (data && data.rates && data.rates.withCommissions) { if (data && data.rates && data.rates.withCommissions) {
const numItems = R.keys(data.rates.withCommissions).length const numItems = R.keys(data.rates.withCommissions).length
if (numItems > 4) { if (numItems > 4) {
setShowExpandBtn(true) setCanExpand(true)
setButtonName(`Show all (${numItems})`)
} }
} }
}, [data]) }, [data])
const toggleExpand = () => {
if (expanded) {
const numItems = R.keys(data.rates.withCommissions).length
setExpanded(false)
setButtonName(`Show all (${numItems})`)
} else {
setExpanded(true)
setButtonName(`Show less`)
}
}
const wallets = fromNamespace('wallets')(data?.config) const wallets = fromNamespace('wallets')(data?.config)
const renderFooterItem = key => { const renderFooterItem = key => {
@ -127,55 +114,58 @@ const Footer = () => {
const makeFooterExpandedClass = () => { const makeFooterExpandedClass = () => {
return { return {
overflow: 'scroll',
// 88px for base height, then add 100 px for each row of items. Each row has 4 items. 5 items makes 2 rows so 288px of height
height: height:
88 + Math.ceil(R.keys(data.rates.withCommissions).length / 4) * 100, R.keys(data.rates.withCommissions).length < 8
? spacer * 12 * 2 + spacer * 2
: spacer * 12 * 3 + spacer * 3,
maxHeight: '50vh', maxHeight: '50vh',
position: 'fixed', position: 'fixed',
left: 0, left: 0,
bottom: 0, bottom: 0,
width: '100vw', width: '100vw',
backgroundColor: white, backgroundColor: white,
textAlign: 'left', textAlign: 'left'
boxShadow: '0px -1px 10px 0px rgba(50, 50, 50, 0.1)'
} }
} }
const expand = () => {
if (canExpand) {
setExpanded(true)
}
}
const shrink = () => {
setExpanded(false)
}
const handleMouseEnter = () => {
setDelayedExpand(
setTimeout(() => {
expand()
}, 300)
)
}
const handleMouseLeave = () => {
clearTimeout(delayedExpand)
shrink()
}
return ( return (
<> <>
<div <div
className={!expanded ? classes.footer : null} onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
className={classes.footer}
style={expanded ? makeFooterExpandedClass() : null}> style={expanded ? makeFooterExpandedClass() : null}>
<div className={classes.content}> <div className={classes.content}>
{!loading && data && ( {!loading && data && (
<> <Grid container spacing={1}>
<Grid container spacing={1}> <Grid container className={classes.footerContainer}>
<Grid container item xs={11} style={{ marginBottom: 18 }}> {R.keys(data.rates.withCommissions).map(key =>
{R.keys(data.rates.withCommissions).map(key => renderFooterItem(key)
renderFooterItem(key)
)}
</Grid>
{/* {renderFooterItem(R.keys(data.rates.withCommissions)[0])} */}
{showExpandBtn && (
<Label1
style={{
textAlign: 'center',
marginBottom: 0,
marginTop: 35
}}>
<Button
onClick={toggleExpand}
size="small"
disableRipple
disableFocusRipple
className={classes.button}>
{buttonName}
</Button>
</Label1>
)} )}
</Grid> </Grid>
</> </Grid>
)} )}
</div> </div>
</div> </div>

View file

@ -4,11 +4,12 @@ import {
offColor, offColor,
errorColor, errorColor,
primaryColor, primaryColor,
white white,
spacer
} from 'src/styling/variables' } from 'src/styling/variables'
const { label1 } = typographyStyles const { label1 } = typographyStyles
export default { const styles = {
label: { label: {
color: offColor color: offColor
}, },
@ -67,7 +68,7 @@ export default {
width: '100vw', width: '100vw',
backgroundColor: white, backgroundColor: white,
textAlign: 'left', textAlign: 'left',
height: 88, height: spacer * 12,
boxShadow: '0px -1px 10px 0px rgba(50, 50, 50, 0.1)' boxShadow: '0px -1px 10px 0px rgba(50, 50, 50, 0.1)'
}, },
content: { content: {
@ -92,5 +93,11 @@ export default {
marginLeft: 6 marginLeft: 6
}, },
marginTop: -20 marginTop: -20
},
footerContainer: {
marginLeft: spacer * 5,
marginBottom: spacer * 2
} }
} }
export default styles

View file

@ -2,7 +2,7 @@ import Grid from '@material-ui/core/Grid'
import { makeStyles } from '@material-ui/core/styles' import { makeStyles } from '@material-ui/core/styles'
import React, { useState } from 'react' import React, { useState } from 'react'
import Alerts from './Alerts' // import Alerts from './Alerts'
import styles from './Dashboard.styles' import styles from './Dashboard.styles'
import SystemStatus from './SystemStatus' import SystemStatus from './SystemStatus'
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
@ -28,14 +28,14 @@ const RightSide = () => {
return ( return (
<> <>
<Grid item xs={6}> <Grid item xs={6}>
<Grid item style={{ marginBottom: 16 }}> {/* <Grid item style={{ marginBottom: 16 }}>
<div className={classes.card}> <div className={classes.card}>
<Alerts <Alerts
cardState={rightSideState.alerts} cardState={rightSideState.alerts}
setRightSideState={setRightSideState} setRightSideState={setRightSideState}
/> />
</div> </div>
</Grid> </Grid> */}
<Grid item> <Grid item>
<div className={classes.card}> <div className={classes.card}>
<SystemStatus <SystemStatus

View file

@ -1,5 +1,4 @@
import { makeStyles } from '@material-ui/core' import { makeStyles } from '@material-ui/core'
import Slider from '@material-ui/core/Slider'
import React from 'react' import React from 'react'
import { ReactComponent as CashIn } from 'src/styling/icons/direction/cash-in.svg' import { ReactComponent as CashIn } from 'src/styling/icons/direction/cash-in.svg'
@ -38,10 +37,8 @@ const useStyles = makeStyles(styles)
const PercentageChart = () => { const PercentageChart = () => {
const classes = useStyles() const classes = useStyles()
const [value, setValue] = React.useState(50)
const handleChange = (event, newValue) => { const value = 50
setValue(newValue)
}
const buildPercentageView = (value, direction) => { const buildPercentageView = (value, direction) => {
switch (direction) { switch (direction) {
@ -72,24 +69,15 @@ const PercentageChart = () => {
return ( return (
<> <>
<Slider
value={value}
onChange={handleChange}
aria-labelledby="continuous-slider"
/>
<div className={classes.wrapper}> <div className={classes.wrapper}>
<div <div
className={classes.percentageBox} className={classes.percentageBox}
style={{ width: `${value}%`, marginRight: 4 }}> style={{ width: `${value}%`, marginRight: 4 }}>
{/* <CashIn />
<span className={classes.label}>{` ${value}%`}</span> */}
{buildPercentageView(value, 'cashIn')} {buildPercentageView(value, 'cashIn')}
</div> </div>
<div <div
className={classes.percentageBox} className={classes.percentageBox}
style={{ width: `${100 - value}%` }}> style={{ width: `${100 - value}%` }}>
{/* <CashOut />
<span className={classes.label}>{` ${100 - value}%`}</span> */}
{buildPercentageView(100 - value, 'cashOut')} {buildPercentageView(100 - value, 'cashOut')}
</div> </div>
</div> </div>

View file

@ -9,7 +9,7 @@ import {
linkSecondaryColor linkSecondaryColor
} from 'src/styling/variables' } from 'src/styling/variables'
export default { const styles = {
titleWrapper: { titleWrapper: {
display: 'flex', display: 'flex',
justifyContent: 'space-between', justifyContent: 'space-between',
@ -78,3 +78,5 @@ export default {
color: linkSecondaryColor color: linkSecondaryColor
} }
} }
export default styles

View file

@ -5,7 +5,7 @@ import {
primaryColor primaryColor
} from 'src/styling/variables' } from 'src/styling/variables'
export default { const styles = {
label: { label: {
margin: 0, margin: 0,
color: offColor color: offColor
@ -35,7 +35,7 @@ export default {
statusHeader: { statusHeader: {
marginLeft: 2 marginLeft: 2
}, },
table: { /* table: {
maxHeight: 440, maxHeight: 440,
'&::-webkit-scrollbar': { '&::-webkit-scrollbar': {
width: 7 width: 7
@ -44,6 +44,18 @@ export default {
backgroundColor: offColor, backgroundColor: offColor,
borderRadius: 5 borderRadius: 5
} }
}, */
// temporary, when notifications are enabled delete this one and decomment above
table: {
maxHeight: 465,
minHeight: 465,
'&::-webkit-scrollbar': {
width: 7
},
'&::-webkit-scrollbar-thumb': {
backgroundColor: offColor,
borderRadius: 5
}
}, },
tableBody: { tableBody: {
overflow: 'auto' overflow: 'auto'
@ -52,3 +64,5 @@ export default {
marginTop: 0 marginTop: 0
} }
} }
export default styles

View file

@ -1,11 +1,11 @@
import { useQuery } from '@apollo/react-hooks' import { useQuery } from '@apollo/react-hooks'
import Button from '@material-ui/core/Button' // import Button from '@material-ui/core/Button'
import Grid from '@material-ui/core/Grid' import Grid from '@material-ui/core/Grid'
import { makeStyles } from '@material-ui/core/styles' import { makeStyles } from '@material-ui/core/styles'
import gql from 'graphql-tag' import gql from 'graphql-tag'
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import ActionButton from 'src/components/buttons/ActionButton' // import ActionButton from 'src/components/buttons/ActionButton'
import { H4, TL2, Label1 } from 'src/components/typography' import { H4, TL2, Label1 } from 'src/components/typography'
import MachinesTable from './MachinesTable' import MachinesTable from './MachinesTable'
@ -14,7 +14,7 @@ import styles from './MachinesTable.styles'
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
// number of machines in the table to render on page load // number of machines in the table to render on page load
const NUM_TO_RENDER = 3 // const NUM_TO_RENDER = 3
const GET_DATA = gql` const GET_DATA = gql`
query getData { query getData {
@ -49,23 +49,23 @@ const SystemStatus = ({ cardState, setRightSideState }) => {
const classes = useStyles() const classes = useStyles()
const { data, loading } = useQuery(GET_DATA) const { data, loading } = useQuery(GET_DATA)
const [showAllItems, setShowAllItems] = useState(false) const [showAllItems, setShowAllItems] = useState(false)
const [showExpandButton, setShowExpandButton] = useState(false) // const [showExpandButton, setShowExpandButton] = useState(false)
const [numToRender, setNumToRender] = useState(NUM_TO_RENDER) // const [numToRender, setNumToRender] = useState(NUM_TO_RENDER)
useEffect(() => { useEffect(() => {
if (showAllItems) { /* if (showAllItems) {
setShowExpandButton(false) setShowExpandButton(false)
setNumToRender(data?.machines.length) setNumToRender(data?.machines.length)
} else if (data && data?.machines.length > numToRender) { } else if (data && data?.machines.length > numToRender) {
setShowExpandButton(true) setShowExpandButton(true)
} } */
if (cardState.cardSize === 'small' || cardState.cardSize === 'default') { if (cardState.cardSize === 'small' || cardState.cardSize === 'default') {
setShowAllItems(false) setShowAllItems(false)
setNumToRender(NUM_TO_RENDER) // setNumToRender(NUM_TO_RENDER)
} }
}, [cardState.cardSize, data, numToRender, showAllItems]) }, [cardState.cardSize, data, /* numToRender, */ showAllItems])
const reset = () => { /* const reset = () => {
setShowAllItems(false) setShowAllItems(false)
setNumToRender(NUM_TO_RENDER) setNumToRender(NUM_TO_RENDER)
setRightSideState({ setRightSideState({
@ -81,7 +81,7 @@ const SystemStatus = ({ cardState, setRightSideState }) => {
systemStatus: { cardSize: 'big', buttonName: 'Show less' }, systemStatus: { cardSize: 'big', buttonName: 'Show less' },
alerts: { cardSize: 'small', buttonName: 'Show alerts' } alerts: { cardSize: 'small', buttonName: 'Show alerts' }
}) })
} } */
// placeholder data // placeholder data
if (data) { if (data) {
@ -92,8 +92,9 @@ const SystemStatus = ({ cardState, setRightSideState }) => {
return ( return (
<> <>
<div style={{ display: 'flex', justifyContent: 'space-between' }}> <div style={{ display: 'flex', justifyContent: 'space-between' }}>
<H4 className={classes.h4}>System status</H4> <H4 className={classes.h4}>System status</H4>{' '}
{(showAllItems || cardState.cardSize === 'small') && ( </div>
{/* {(showAllItems || cardState.cardSize === 'small') && (
<> <>
<Label1 <Label1
style={{ style={{
@ -112,7 +113,7 @@ const SystemStatus = ({ cardState, setRightSideState }) => {
</Label1> </Label1>
</> </>
)} )}
</div> </div> */}
{!loading && cardState.cardSize !== 'small' && ( {!loading && cardState.cardSize !== 'small' && (
<> <>
<Grid container spacing={1}> <Grid container spacing={1}>
@ -127,21 +128,22 @@ const SystemStatus = ({ cardState, setRightSideState }) => {
<Label1 style={{ display: 'inline' }}> server version</Label1> <Label1 style={{ display: 'inline' }}> server version</Label1>
</Grid> </Grid>
<Grid item xs={4}> <Grid item xs={4}>
<ActionButton {/* <ActionButton
color="primary" color="primary"
className={classes.actionButton} className={classes.actionButton}
onClick={() => console.log('Upgrade button clicked')}> onClick={() => console.log('Upgrade button clicked')}>
Update to v10.6.0 Update to v10.6.0
</ActionButton> </ActionButton> */}
</Grid> </Grid>
</Grid> </Grid>
<Grid container spacing={1} style={{ marginTop: 23 }}> <Grid container spacing={1} style={{ marginTop: 23 }}>
<Grid item xs={12}> <Grid item xs={12}>
<MachinesTable <MachinesTable
numToRender={numToRender} /* numToRender={numToRender} */
numToRender={Infinity}
machines={data?.machines ?? []} machines={data?.machines ?? []}
/> />
{showExpandButton && ( {/* {showExpandButton && (
<> <>
<Label1 style={{ textAlign: 'center', marginBottom: 0 }}> <Label1 style={{ textAlign: 'center', marginBottom: 0 }}>
<Button <Button
@ -154,7 +156,7 @@ const SystemStatus = ({ cardState, setRightSideState }) => {
</Button> </Button>
</Label1> </Label1>
</> </>
)} )} */}
</Grid> </Grid>
</Grid> </Grid>
</> </>

View file

@ -1,6 +1,8 @@
export default { const styles = {
cashbox: { cashbox: {
width: 80, width: 80,
height: 36 height: 36
} }
} }
export default styles

View file

@ -1,6 +1,6 @@
import { zircon } from 'src/styling/variables' import { zircon } from 'src/styling/variables'
export default { const styles = {
expandButton: { expandButton: {
outline: 'none', outline: 'none',
border: 'none', border: 'none',
@ -41,3 +41,5 @@ export default {
flexDirection: 'column' flexDirection: 'column'
}) })
} }
export default styles

View file

@ -3,7 +3,7 @@ import { offColor } from 'src/styling/variables'
const { p } = typographyStyles const { p } = typographyStyles
export default { const styles = {
wrapper: { wrapper: {
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
@ -82,3 +82,5 @@ export default {
width: 215 width: 215
} }
} }
export default styles

View file

@ -6,7 +6,7 @@ import {
comet comet
} from 'src/styling/variables' } from 'src/styling/variables'
export default { const styles = {
grid: { grid: {
flex: 1, flex: 1,
height: '100%' height: '100%'
@ -71,3 +71,5 @@ export default {
marginRight: 8 marginRight: 8
} }
} }
export default styles

View file

@ -51,18 +51,18 @@ const useStyles = makeStyles({
}) })
const tree = [ const tree = [
{ /* {
key: 'dashboard', key: 'dashboard',
label: 'Dashboard', label: 'Dashboard',
route: '/dashboard', route: '/dashboard',
component: Dashboard component: Dashboard
}, }, */
{ /* {
key: 'machines', key: 'machines',
label: 'Machines', label: 'Machines',
route: '/machines', route: '/machines',
component: Machines component: Machines
}, }, */
{ {
key: 'transactions', key: 'transactions',
label: 'Transactions', label: 'Transactions',
@ -315,6 +315,8 @@ const Routes = () => {
<Route exact path="/"> <Route exact path="/">
<Redirect to={{ pathname: '/transactions' }} /> <Redirect to={{ pathname: '/transactions' }} />
</Route> </Route>
<Route path="/dashboard" component={Dashboard} />
<Route path="/machines" component={Machines} />
<Route path="/wizard" component={Wizard} /> <Route path="/wizard" component={Wizard} />
<Route path="/register" component={AuthRegister} /> <Route path="/register" component={AuthRegister} />
<Route path="/configmigration" component={ConfigMigration} /> <Route path="/configmigration" component={ConfigMigration} />