feat: add dashboard states for empty transactions and empty machine list

This commit is contained in:
Sérgio Salgado 2021-12-02 17:30:50 +00:00
parent 31dcf890de
commit b35abca622
6 changed files with 155 additions and 53 deletions

View file

@ -1,4 +1,5 @@
import { makeStyles } from '@material-ui/core' import { makeStyles } from '@material-ui/core'
import classNames from 'classnames'
import React, { memo } from 'react' import React, { memo } from 'react'
import { H4 } from 'src/components/typography' import { H4 } from 'src/components/typography'
@ -16,11 +17,11 @@ const styles = {
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
const EmptyTable = memo(({ message }) => { const EmptyTable = memo(({ message, className }) => {
const classes = useStyles() const classes = useStyles()
return ( return (
<div className={classes.emptyTable}> <div className={classNames(className, classes.emptyTable)}>
<EmptyTableIcon /> <EmptyTableIcon />
<H4>{message}</H4> <H4>{message}</H4>
</div> </div>

View file

@ -1,9 +1,16 @@
import { useQuery } from '@apollo/react-hooks'
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 classnames from 'classnames' import classnames from 'classnames'
import React from 'react' import gql from 'graphql-tag'
import * as R from 'ramda'
import React, { useState } from 'react'
import { useHistory } from 'react-router-dom'
import { Button } from 'src/components/buttons'
import TitleSection from 'src/components/layout/TitleSection' import TitleSection from 'src/components/layout/TitleSection'
import { H1, Info2, TL2, Label1 } from 'src/components/typography'
import AddMachine from 'src/pages/AddMachine'
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'
@ -13,40 +20,88 @@ import LeftSide from './LeftSide'
import RightSide from './RightSide' import RightSide from './RightSide'
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
const Dashboard = () => { const GET_DATA = gql`
const classes = useStyles() query getData {
machines {
name
}
serverVersion
}
`
return ( const Dashboard = () => {
<> const history = useHistory()
<TitleSection title="Dashboard"> const classes = useStyles()
<div className={classes.headerLabels}> const [open, setOpen] = useState(false)
<div
className={classnames( const { data, loading } = useQuery(GET_DATA)
classes.headerLabelContainer,
classes.headerLabelContainerMargin const onPaired = machine => {
)}> setOpen(false)
<TxOutIcon /> history.push('/maintenance/machine-status', { id: machine.deviceId })
<span className={classes.headerLabelSpan}>Cash-out</span> }
return !loading ? (
!R.isEmpty(data.machines) ? (
<>
<TitleSection title="Dashboard">
<div className={classes.headerLabels}>
<>
<div
className={classnames(
classes.headerLabelContainer,
classes.headerLabelContainerMargin
)}>
<TxOutIcon />
<span className={classes.headerLabelSpan}>Cash-out</span>
</div>
<div className={classes.headerLabelContainer}>
<TxInIcon />
<span className={classes.headerLabelSpan}>Cash-in</span>
</div>
</>
</div> </div>
<div className={classes.headerLabelContainer}> </TitleSection>
<TxInIcon /> <div className={classes.root}>
<span className={classes.headerLabelSpan}>Cash-in</span> <Grid container>
<Grid container direction="column" item xs={6}>
<LeftSide />
</Grid>
<Grid container direction="column" item xs={6}>
<RightSide />
</Grid>
</Grid>
</div>
<Footer />
</>
) : (
<>
{open && (
<AddMachine close={() => setOpen(false)} onPaired={onPaired} />
)}
<TitleSection title="Dashboard">
<div className={classes.headerLabels}>
<span>
<TL2 className={classes.inline}>{data?.serverVersion}</TL2>{' '}
<Label1 className={classes.inline}> server version</Label1>
</span>
</div>
</TitleSection>
<div className={classes.emptyMachinesRoot}>
<div className={classes.emptyMachinesContent}>
<H1 className={classes.offColor}>No machines on your system yet</H1>
<Info2 className={classes.offColor}>
To fully take advantage of Lamassu Admin, add a new machine to
your system
</Info2>
<Button onClick={() => setOpen(true)}>+ Add new machine</Button>
</div> </div>
</div> </div>
</TitleSection> <Footer />
</>
<div className={classes.root}> )
<Grid container> ) : (
<Grid container direction="column" item xs={6}> <></>
<LeftSide />
</Grid>
<Grid container direction="column" item xs={6}>
<RightSide />
</Grid>
</Grid>
</div>
<Footer />
</>
) )
} }

View file

@ -1,5 +1,12 @@
import typographyStyles from 'src/components/typography/styles' import typographyStyles from 'src/components/typography/styles'
import { spacer, white, primaryColor } from 'src/styling/variables' import {
spacer,
white,
primaryColor,
zircon,
zircon2,
offDarkColor
} from 'src/styling/variables'
const { label1 } = typographyStyles const { label1 } = typographyStyles
const styles = { const styles = {
@ -23,6 +30,11 @@ const styles = {
display: 'flex', display: 'flex',
marginBottom: 120 marginBottom: 120
}, },
emptyMachinesRoot: {
height: 300,
backgroundColor: zircon,
border: `solid 2px ${zircon2}`
},
card: { card: {
wordWrap: 'break-word', wordWrap: 'break-word',
boxShadow: '0 0 4px 0 rgba(0, 0, 0, 0.08)', boxShadow: '0 0 4px 0 rgba(0, 0, 0, 0.08)',
@ -75,6 +87,25 @@ const styles = {
displayFlex: { displayFlex: {
display: 'flex', display: 'flex',
flexDirection: 'column' flexDirection: 'column'
},
inline: {
display: 'inline'
},
emptyMachinesContent: {
display: 'flex',
flexDirection: 'column',
height: '100%',
justifyContent: 'center',
alignItems: 'center',
'& > :first-child': {
marginTop: 0
},
'& > *': {
marginTop: 25
}
},
offColor: {
color: offDarkColor
} }
} }

View file

@ -10,7 +10,7 @@ import styles from './SystemPerformance.styles'
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
const ranges = ['Month', 'Week', 'Day'] const ranges = ['Month', 'Week', 'Day']
const Nav = ({ handleSetRange }) => { const Nav = ({ handleSetRange, showPicker }) => {
const classes = useStyles() const classes = useStyles()
const [clickedItem, setClickedItem] = useState('Day') const [clickedItem, setClickedItem] = useState('Day')
@ -25,22 +25,24 @@ const Nav = ({ handleSetRange }) => {
<div className={classes.titleAndButtonsContainer}> <div className={classes.titleAndButtonsContainer}>
<H4 className={classes.h4}>{'System performance'}</H4> <H4 className={classes.h4}>{'System performance'}</H4>
</div> </div>
<div className={classes.navContainer}> {showPicker && (
{ranges.map((it, idx) => { <div className={classes.navContainer}>
return ( {ranges.map((it, idx) => {
<div return (
key={idx} <div
onClick={e => handleClick(e.target.innerText)} key={idx}
className={ onClick={e => handleClick(e.target.innerText)}
isSelected(it) className={
? classnames(classes.newHighlightedLabel, classes.navButton) isSelected(it)
: classnames(classes.label, classes.navButton) ? classnames(classes.newHighlightedLabel, classes.navButton)
}> : classnames(classes.label, classes.navButton)
{it} }>
</div> {it}
) </div>
})} )
</div> })}
</div>
)}
</div> </div>
) )
} }

View file

@ -8,6 +8,7 @@ import gql from 'graphql-tag'
import * as R from 'ramda' import * as R from 'ramda'
import React, { useState } from 'react' import React, { useState } from 'react'
import { EmptyTable } from 'src/components/table'
import { Label1, Label2 } from 'src/components/typography/index' import { Label1, Label2 } from 'src/components/typography/index'
import { ReactComponent as PercentDownIcon } from 'src/styling/icons/dashboard/down.svg' import { ReactComponent as PercentDownIcon } from 'src/styling/icons/dashboard/down.svg'
import { ReactComponent as PercentNeutralIcon } from 'src/styling/icons/dashboard/equal.svg' import { ReactComponent as PercentNeutralIcon } from 'src/styling/icons/dashboard/equal.svg'
@ -171,8 +172,17 @@ const SystemPerformance = () => {
return ( return (
<> <>
<Nav handleSetRange={setSelectedRange} /> <Nav
{!loading && ( showPicker={!loading && !R.isEmpty(data.transactions)}
handleSetRange={setSelectedRange}
/>
{!loading && R.isEmpty(data.transactions) && (
<EmptyTable
className={classes.emptyTransactions}
message="No transactions so far"
/>
)}
{!loading && !R.isEmpty(data.transactions) && (
<> <>
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid item xs={3}> <Grid item xs={3}>

View file

@ -134,6 +134,9 @@ const styles = {
labelMargin: { labelMargin: {
marginBottom: 20, marginBottom: 20,
marginRight: 32 marginRight: 32
},
emptyTransactions: {
paddingTop: 40
} }
} }