Merge pull request #969 from chaotixkilla/feat-empty-dashboard-state
Dashboard show empty machine and transaction lists
This commit is contained in:
commit
509b696181
6 changed files with 155 additions and 53 deletions
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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 />
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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}>
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,9 @@ const styles = {
|
||||||
labelMargin: {
|
labelMargin: {
|
||||||
marginBottom: 20,
|
marginBottom: 20,
|
||||||
marginRight: 32
|
marginRight: 32
|
||||||
|
},
|
||||||
|
emptyTransactions: {
|
||||||
|
paddingTop: 40
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue