partial: Maintenance css migration

This commit is contained in:
Rafael Taranto 2025-05-06 18:14:49 +01:00
parent b95dd5cbbf
commit a90833726e
12 changed files with 176 additions and 725 deletions

View file

@ -1,87 +1,12 @@
import { makeStyles } from '@mui/styles'
import Chip from '@mui/material/Chip' import Chip from '@mui/material/Chip'
import * as R from 'ramda' import * as R from 'ramda'
import React from 'react' import React from 'react'
import { Label1, TL2 } from 'src/components/typography' import { Label1, TL2 } from 'src/components/typography'
import { CashOut } from 'src/components/inputs' import { CashOut } from 'src/components/inputs'
import { offDarkColor } from 'src/styling/variables'
import { fromNamespace } from 'src/utils/config' import { fromNamespace } from 'src/utils/config'
import { getCashUnitCapacity, modelPrettifier } from 'src/utils/machine' import { getCashUnitCapacity, modelPrettifier } from 'src/utils/machine'
const styles = {
wrapper: {
display: 'flex',
flexDirection: 'row',
marginTop: 12,
marginBottom: 16,
'& > *': {
marginRight: 40
},
'& > *:last-child': {
marginRight: 0
},
minHeight: 120
},
row: {
display: 'flex',
flexDirection: 'row'
},
col: {
display: 'flex',
flexDirection: 'column'
},
machineData: {
display: 'flex',
flexDirection: 'column',
minWidth: 210
},
billList: ({ hideMachineData }) => ({
display: 'flex',
flexDirection: 'column',
minWidth: hideMachineData ? 60 : 160,
'& > span': {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
'& > p': {
minWidth: 30
}
}
}),
unitList: {
display: 'flex',
flexDirection: 'row',
'& > *': {
marginRight: 20
},
'& > *:last-child': {
marginRight: 0
},
marginTop: 10
},
verticalLine: {
height: '100%',
width: 1,
backgroundColor: offDarkColor
},
label: {
marginBottom: 10
},
loadingBoxes: {
display: 'flex',
flexDirection: 'column',
'& > *': {
marginBottom: 20
},
'& > *:last-child': {
marginBottom: 0
}
}
}
const useStyles = makeStyles(styles)
const CashUnitDetails = ({ const CashUnitDetails = ({
machine, machine,
bills, bills,
@ -89,38 +14,40 @@ const CashUnitDetails = ({
config, config,
hideMachineData = false hideMachineData = false
}) => { }) => {
const classes = useStyles({ hideMachineData })
const billCount = R.countBy(it => it.fiat)(bills) const billCount = R.countBy(it => it.fiat)(bills)
const fillingPercentageSettings = fromNamespace('notifications', config) const fillingPercentageSettings = fromNamespace('notifications', config)
const cashout = fromNamespace('cashOut')(config) const cashout = fromNamespace('cashOut')(config)
const getCashoutSettings = id => fromNamespace(id)(cashout) const getCashoutSettings = id => fromNamespace(id)(cashout)
const minWidth = hideMachineData ? 'min-w-15' : 'min-w-40'
const VerticalLine = () => <span className="h-full w-[1px] bg-comet2" />
return ( return (
<div className={classes.wrapper}> <div className="flex flex-row mt-3 mb-4 gap-10 min-h-30">
{!hideMachineData && ( {!hideMachineData && (
<div className={classes.machineData}> <div className="min-w-52">
<Label1>Machine Model</Label1> <Label1>Machine Model</Label1>
<span>{modelPrettifier[machine.model]}</span> <span>{modelPrettifier[machine.model]}</span>
</div> </div>
)} )}
<div className={classes.billList}> <div className={`flex flex-col ${minWidth}`}>
<Label1>Cash box</Label1> <Label1>Cash box</Label1>
{R.isEmpty(billCount) && <TL2 noMargin>Empty</TL2>} {R.isEmpty(billCount) && <TL2 noMargin>Empty</TL2>}
{R.keys(billCount).map((it, idx) => ( {R.keys(billCount).map((it, idx) => (
<span key={idx}> <span className="flex items-center" key={idx}>
<TL2 noMargin>{billCount[it]}</TL2> <TL2 className="min-w-7" noMargin>
{billCount[it]}
</TL2>
<Chip label={`${it} ${currency}`} /> <Chip label={`${it} ${currency}`} />
</span> </span>
))} ))}
</div> </div>
<div className={classes.unitList}> <div className="flex gap-5">
{machine.numberOfRecyclers === 0 && {machine.numberOfRecyclers === 0 &&
R.map(it => ( R.map(it => (
<> <>
<div className={classes.col}> <div className="flex flex-col gap-2">
<Label1 <Label1 noMargin>{`Cassette ${it}`}</Label1>
noMargin
className={classes.label}>{`Cassette ${it}`}</Label1>
<CashOut <CashOut
width={60} width={60}
height={40} height={40}
@ -137,18 +64,14 @@ const CashUnitDetails = ({
capacity={getCashUnitCapacity(machine.model, 'cassette')} capacity={getCashUnitCapacity(machine.model, 'cassette')}
/> />
</div> </div>
{it !== machine.numberOfCassettes && ( {it !== machine.numberOfCassettes && <VerticalLine />}
<span className={classes.verticalLine} />
)}
</> </>
))(R.range(1, machine.numberOfCassettes + 1))} ))(R.range(1, machine.numberOfCassettes + 1))}
{machine.numberOfRecyclers > 0 && ( {machine.numberOfRecyclers > 0 && (
<> <>
<div className={classes.col}> <div className="flex flex-col gap-2">
<Label1 <Label1 noMargin>{`Loading boxes`}</Label1>
noMargin <div className="flex flex-col gap-5">
className={classes.label}>{`Loading boxes`}</Label1>
<div className={classes.loadingBoxes}>
{R.range(1, machine.numberOfCassettes + 1).map((it, idx) => ( {R.range(1, machine.numberOfCassettes + 1).map((it, idx) => (
<CashOut <CashOut
key={idx} key={idx}
@ -171,18 +94,18 @@ const CashUnitDetails = ({
))} ))}
</div> </div>
</div> </div>
<span className={classes.verticalLine} /> <VerticalLine />
{R.map(it => ( {R.map(it => (
<> <>
<div className={classes.col}> <div className="flex flex-col gap-2">
<Label1 noMargin className={classes.label}> <Label1 noMargin>
{`Recycler ${ {`Recycler ${
machine.model === 'aveiro' machine.model === 'aveiro'
? `${it} f/r` ? `${it} f/r`
: `${it * 2 - 1} - ${it * 2}` : `${it * 2 - 1} - ${it * 2}`
}`} }`}
</Label1> </Label1>
<div className={classes.loadingBoxes}> <div className="flex flex-col gap-5">
<CashOut <CashOut
width={60} width={60}
height={40} height={40}
@ -219,9 +142,7 @@ const CashUnitDetails = ({
/> />
</div> </div>
</div> </div>
{it !== machine.numberOfRecyclers / 2 && ( {it !== machine.numberOfRecyclers / 2 && <VerticalLine />}
<span className={classes.verticalLine} />
)}
</> </>
))(R.range(1, machine.numberOfRecyclers / 2 + 1))} ))(R.range(1, machine.numberOfRecyclers / 2 + 1))}
</> </>

View file

@ -1,6 +1,5 @@
import { useQuery, useMutation, gql } from '@apollo/client' import { useQuery, useMutation, gql } from '@apollo/client'
import DialogActions from '@mui/material/DialogActions' import DialogActions from '@mui/material/DialogActions'
import { makeStyles } from '@mui/styles'
import * as R from 'ramda' import * as R from 'ramda'
import React, { useState } from 'react' import React, { useState } from 'react'
import LogsDowloaderPopover from 'src/components/LogsDownloaderPopper' import LogsDowloaderPopover from 'src/components/LogsDownloaderPopper'
@ -21,14 +20,11 @@ import { MANUAL, AUTOMATIC } from 'src/utils/constants'
import { onlyFirstToUpper } from 'src/utils/string' import { onlyFirstToUpper } from 'src/utils/string'
import CashUnitDetails from './CashUnitDetails' import CashUnitDetails from './CashUnitDetails'
import styles from './CashUnits.styles'
import CashCassettesFooter from './CashUnitsFooter' import CashCassettesFooter from './CashUnitsFooter'
import CashboxHistory from './CashboxHistory' import CashboxHistory from './CashboxHistory'
import Wizard from './Wizard/Wizard' import Wizard from './Wizard/Wizard'
import helper from './helper' import helper from './helper'
const useStyles = makeStyles(styles)
const GET_MACHINES_AND_CONFIG = gql` const GET_MACHINES_AND_CONFIG = gql`
query getData($billFilters: JSONObject) { query getData($billFilters: JSONObject) {
machines { machines {
@ -114,7 +110,6 @@ const widths = {
} }
const CashCassettes = () => { const CashCassettes = () => {
const classes = useStyles()
const [showHistory, setShowHistory] = useState(false) const [showHistory, setShowHistory] = useState(false)
const [editingSchema, setEditingSchema] = useState(null) const [editingSchema, setEditingSchema] = useState(null)
const [selectedRadio, setSelectedRadio] = useState(null) const [selectedRadio, setSelectedRadio] = useState(null)
@ -219,7 +214,7 @@ const CashCassettes = () => {
{ {
component: showHistory ? ( component: showHistory ? (
<LogsDowloaderPopover <LogsDowloaderPopover
className={classes.downloadLogsButton} className="ml-4"
title="Download logs" title="Download logs"
name="cashboxHistory" name="cashboxHistory"
query={GET_BATCHES_CSV} query={GET_BATCHES_CSV}
@ -232,8 +227,7 @@ const CashCassettes = () => {
) )
} }
]} ]}
iconClassName={classes.listViewButton} className="flex items-center mr-[1px]"
className={classes.tableWidth}
appendix={ appendix={
<HelpTooltip width={220}> <HelpTooltip width={220}>
<P> <P>
@ -248,18 +242,17 @@ const CashCassettes = () => {
</HelpTooltip> </HelpTooltip>
}> }>
{!showHistory && ( {!showHistory && (
<div className="flex items-center justify-end"> <div className="flex flex-col items-end">
<Label1 className={classes.cashboxReset}>Cash box resets</Label1> <Label1 noMargin className="text-comet">
Cash box resets
</Label1>
<div className="flex items-center justify-end -mr-1"> <div className="flex items-center justify-end -mr-1">
{cashboxReset && ( {cashboxReset && (
<P className={classes.selection}> <P noMargin className="mr-2">
{onlyFirstToUpper(cashboxReset)} {onlyFirstToUpper(cashboxReset)}
</P> </P>
)} )}
<IconButton <IconButton onClick={() => setEditingSchema(true)} size="large">
onClick={() => setEditingSchema(true)}
className={classes.button}
size="large">
<EditIcon /> <EditIcon />
</IconButton> </IconButton>
</div> </div>
@ -275,7 +268,7 @@ const CashCassettes = () => {
Details={InnerCashUnitDetails} Details={InnerCashUnitDetails}
emptyText="No machines so far" emptyText="No machines so far"
expandable expandable
tableClassName={classes.dataTable} tableClassName="mb-20"
/> />
{data && R.isEmpty(machines) && ( {data && R.isEmpty(machines) && (
@ -315,7 +308,7 @@ const CashCassettes = () => {
width={478} width={478}
handleClose={() => setEditingSchema(null)} handleClose={() => setEditingSchema(null)}
open={true}> open={true}>
<P className={classes.descriptions}> <P className="text-comet mt-0">
We can automatically assume you emptied a bill validator's cash We can automatically assume you emptied a bill validator's cash
box when the machine detects that it has been removed. box when the machine detects that it has been removed.
</P> </P>
@ -324,9 +317,8 @@ const CashCassettes = () => {
value={selectedRadio ?? cashboxReset} value={selectedRadio ?? cashboxReset}
options={[radioButtonOptions[0]]} options={[radioButtonOptions[0]]}
onChange={handleRadioButtons} onChange={handleRadioButtons}
className={classes.radioButtons}
/> />
<P className={classes.descriptions}> <P className="text-comet mt-0">
Assume the cash box is emptied whenever it's removed, creating a Assume the cash box is emptied whenever it's removed, creating a
new batch on the history screen and setting its current balance to new batch on the history screen and setting its current balance to
zero. zero.
@ -336,14 +328,13 @@ const CashCassettes = () => {
value={selectedRadio ?? cashboxReset} value={selectedRadio ?? cashboxReset}
options={[radioButtonOptions[1]]} options={[radioButtonOptions[1]]}
onChange={handleRadioButtons} onChange={handleRadioButtons}
className={classes.radioButtons}
/> />
<P className={classes.descriptions}> <P className="text-comet mt-0">
Cash boxes won't be assumed emptied when removed, nor their counts Cash boxes won't be assumed emptied when removed, nor their counts
modified. Instead, to update the count and create a new batch, modified. Instead, to update the count and create a new batch,
you'll click the 'Edit' button on this panel. you'll click the 'Edit' button on this panel.
</P> </P>
<DialogActions className={classes.actions}> <DialogActions>
<Button onClick={() => saveCashboxOption(selectedRadio)}> <Button onClick={() => saveCashboxOption(selectedRadio)}>
Confirm Confirm
</Button> </Button>

View file

@ -1,33 +0,0 @@
import { offColor, offDarkColor } from 'src/styling/variables'
export default {
cashbox: {
height: 36
},
tBody: {
maxHeight: 'calc(100vh - 350px)',
overflow: 'auto'
},
tableWidth: {
display: 'flex',
alignItems: 'center',
marginRight: 1
},
descriptions: {
color: offColor,
marginTop: 0
},
cashboxReset: {
color: offColor,
margin: [[13, 0, -5, 20]]
},
selection: {
marginRight: 12
},
downloadLogsButton: {
marginLeft: 13
},
dataTable: {
marginBottom: 80
}
}

View file

@ -1,4 +1,3 @@
import { makeStyles } from '@mui/styles'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import * as R from 'ramda' import * as R from 'ramda'
import React from 'react' import React from 'react'
@ -9,10 +8,6 @@ import TxOutIcon from 'src/styling/icons/direction/cash-out.svg?react'
import { fromNamespace } from 'src/utils/config' import { fromNamespace } from 'src/utils/config'
import { numberToFiatAmount } from 'src/utils/number' import { numberToFiatAmount } from 'src/utils/number'
import styles from './CashUnitsFooter.styles'
const useStyles = makeStyles(styles)
const CashCassettesFooter = ({ const CashCassettesFooter = ({
machines, machines,
config, config,
@ -20,7 +15,6 @@ const CashCassettesFooter = ({
bills, bills,
deviceIds deviceIds
}) => { }) => {
const classes = useStyles()
const cashout = config && fromNamespace('cashOut')(config) const cashout = config && fromNamespace('cashOut')(config)
const getCashoutSettings = id => fromNamespace(id)(cashout) const getCashoutSettings = id => fromNamespace(id)(cashout)
const cashoutReducerFn = ( const cashoutReducerFn = (
@ -84,33 +78,33 @@ const CashCassettesFooter = ({
).toFormat(0) ).toFormat(0)
return ( return (
<div className={classes.footerContainer}> <div className="fixed h-16 left-0 bottom-0 w-[100vw] bg-white flex justify-around shadow-2xl">
<div className={classes.footerContent}> <div className="w-300 max-h-16 flex fixed justify-around">
<Info3 className={classes.footerLabel}>Cash value in System</Info3> <Info3 className="text-comet self-center">Cash value in System</Info3>
<div className={classes.flex}> <div className="flex">
<TxInIcon className={classes.icon} /> <TxInIcon className="self-center h-5 w-5 mr-2" />
<Info2 className={classes.iconLabel}>Cash-in:</Info2> <Info2 className="self-center mr-2">Cash-in:</Info2>
<Info1 className={classes.valueDisplay}> <Info1 className="self-center">
{numberToFiatAmount(totalInCashBox)} {currencyCode} {numberToFiatAmount(totalInCashBox)} {currencyCode}
</Info1> </Info1>
</div> </div>
<div className={classes.flex}> <div className="flex gap-2">
<TxOutIcon className={classes.icon} /> <TxOutIcon className="self-center h-5 w-5" />
<Info2 className={classes.iconLabel}>Cash-out:</Info2> <Info2 className="self-center">Cash-out:</Info2>
<Info1 className={classes.valueDisplay}> <Info1 className="self-center">
{numberToFiatAmount(totalInCassettes)} {currencyCode} {numberToFiatAmount(totalInCassettes)} {currencyCode}
</Info1> </Info1>
</div> </div>
<div className={classes.flex}> <div className="flex gap-2">
<TxOutIcon className={classes.icon} /> <TxOutIcon className="self-center h-5 w-5" />
<Info2 className={classes.iconLabel}>Recycle:</Info2> <Info2 className="self-center">Recycle:</Info2>
<Info1 className={classes.valueDisplay}> <Info1 className="self-center">
{numberToFiatAmount(totalInRecyclers)} {currencyCode} {numberToFiatAmount(totalInRecyclers)} {currencyCode}
</Info1> </Info1>
</div> </div>
<div className={classes.flex}> <div className="flex gap-2">
<Info2 className={classes.iconLabel}>Total:</Info2> <Info2 className="self-center">Total:</Info2>
<Info1 className={classes.valueDisplay}> <Info1 className="self-center">
{numberToFiatAmount(total)} {currencyCode} {numberToFiatAmount(total)} {currencyCode}
</Info1> </Info1>
</div> </div>

View file

@ -1,42 +0,0 @@
import { comet } from 'src/styling/variables'
export default {
footerLabel: {
color: comet,
alignSelf: 'center'
},
footerContent: {
width: 1200,
maxHeight: 64,
display: 'flex',
justifyContent: 'space-around',
position: 'fixed'
},
footerContainer: {
position: 'fixed',
height: 64,
left: 0,
bottom: 0,
width: '100vw',
backgroundColor: 'white',
display: 'flex',
justifyContent: 'space-around',
boxShadow: [[0, -1, 10, 0, 'rgba(50, 50, 50, 0.1)']]
},
flex: {
display: 'flex'
},
icon: {
alignSelf: 'center',
height: 20,
width: 20,
marginRight: 8
},
iconLabel: {
alignSelf: 'center',
marginRight: 8
},
valueDisplay: {
alignSelf: 'center'
}
}

View file

@ -1,17 +1,11 @@
import { useQuery, gql } from "@apollo/client"; import { useQuery, gql } from '@apollo/client'
import { makeStyles } from '@mui/styles'
import * as R from 'ramda' import * as R from 'ramda'
import React from 'react' import React from 'react'
// import * as Yup from 'yup'
// import { Link, IconButton } from 'src/components/buttons'
// import { TextInput } from 'src/components/inputs'
import DataTable from 'src/components/tables/DataTable' import DataTable from 'src/components/tables/DataTable'
import TxInIcon from 'src/styling/icons/direction/cash-in.svg?react' import TxInIcon from 'src/styling/icons/direction/cash-in.svg?react'
import TxOutIcon from 'src/styling/icons/direction/cash-out.svg?react' import TxOutIcon from 'src/styling/icons/direction/cash-out.svg?react'
import { NumberInput } from 'src/components/inputs/formik' import { NumberInput } from 'src/components/inputs/formik'
// import EditIconDisabled from 'src/styling/icons/action/edit/disabled.svg?react'
// import EditIcon from 'src/styling/icons/action/edit/enabled.svg?react'
import { formatDate } from 'src/utils/timezones' import { formatDate } from 'src/utils/timezones'
const GET_BATCHES = gql` const GET_BATCHES = gql`
@ -29,55 +23,9 @@ const GET_BATCHES = gql`
} }
` `
/* const EDIT_BATCH = gql`
mutation editBatch($id: ID, $performedBy: String) {
editBatch(id: $id, performedBy: $performedBy) {
id
}
}
` */
const styles = {
operationType: {
marginLeft: 8
},
operationTypeWrapper: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center'
},
saveAndCancel: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between'
},
tableWrapper: {
display: 'flex',
flexDirection: 'column',
flex: 1,
marginBottom: 80
}
}
/* const schema = Yup.object().shape({
performedBy: Yup.string().nullable()
}) */
const useStyles = makeStyles(styles)
const CashboxHistory = ({ machines, currency, timezone }) => { const CashboxHistory = ({ machines, currency, timezone }) => {
const classes = useStyles()
/* const [error, setError] = useState(false)
const [field, setField] = useState(null)
const [editing, setEditing] = useState(false) */
const { data: batchesData, loading: batchesLoading } = useQuery(GET_BATCHES) const { data: batchesData, loading: batchesLoading } = useQuery(GET_BATCHES)
/* const [editBatch] = useMutation(EDIT_BATCH, {
refetchQueries: () => ['cashboxBatches']
}) */
const loading = batchesLoading const loading = batchesLoading
const batches = R.path(['cashboxBatches'])(batchesData) const batches = R.path(['cashboxBatches'])(batchesData)
@ -89,18 +37,14 @@ const CashboxHistory = ({ machines, currency, timezone }) => {
`cash-cassette-${i}-refill`, `cash-cassette-${i}-refill`,
<> <>
<TxOutIcon /> <TxOutIcon />
<span className={classes.operationType}> <span>Cash cassette {i} refill</span>
Cash cassette {i} refill
</span>
</> </>
), ),
R.assoc( R.assoc(
`cash-cassette-${i}-empty`, `cash-cassette-${i}-empty`,
<> <>
<TxOutIcon /> <TxOutIcon />
<span className={classes.operationType}> <span>Cash cassette {i} emptied</span>
Cash cassette {i} emptied
</span>
</> </>
) )
)(ret), )(ret),
@ -108,35 +52,13 @@ const CashboxHistory = ({ machines, currency, timezone }) => {
'cash-box-empty': ( 'cash-box-empty': (
<> <>
<TxInIcon /> <TxInIcon />
<span className={classes.operationType}>Cash box emptied</span> <span>Cash box emptied</span>
</> </>
) )
}, },
R.range(1, 5) R.range(1, 5)
) )
/* const save = row => {
const performedBy = field.performedBy === '' ? null : field.performedBy
schema
.isValid(field)
.then(() => {
setError(false)
editBatch({
variables: { id: row.id, performedBy: performedBy }
})
})
.catch(setError(true))
return close()
}
const close = () => {
setEditing(false)
setField(null)
}
const notEditing = id => field?.id !== id */
const elements = [ const elements = [
{ {
name: 'operation', name: 'operation',
@ -144,7 +66,7 @@ const CashboxHistory = ({ machines, currency, timezone }) => {
width: 200, width: 200,
textAlign: 'left', textAlign: 'left',
view: it => ( view: it => (
<div className={classes.operationTypeWrapper}> <div className="flex items-center gap-2">
{getOperationRender[it.operationType]} {getOperationRender[it.operationType]}
</div> </div>
) )
@ -198,57 +120,10 @@ const CashboxHistory = ({ machines, currency, timezone }) => {
textAlign: 'right', textAlign: 'right',
view: it => formatDate(it.created, timezone, 'HH:mm') view: it => formatDate(it.created, timezone, 'HH:mm')
} }
/* {
name: 'performedBy',
header: 'Performed by',
width: 180,
textAlign: 'left',
view: it => {
if (notEditing(it.id))
return R.isNil(it.performedBy) ? 'Unknown entity' : it.performedBy
return (
<TextInput
onChange={e => setField({ ...field, performedBy: e.target.value })}
error={error}
width={190 * 0.85}
value={field?.performedBy}
/>
)
}
},
{
name: '',
header: 'Edit',
width: 80,
textAlign: 'right',
view: it => {
if (notEditing(it.id))
return (
<IconButton
disabled={editing}
onClick={() => {
setField({ id: it.id, performedBy: it.performedBy })
setEditing(true)
}}>
{editing ? <EditIconDisabled /> : <EditIcon />}
</IconButton>
)
return (
<div className={classes.saveAndCancel}>
<Link type="submit" color="primary" onClick={() => save(it)}>
Save
</Link>
<Link color="secondary" onClick={close}>
Cancel
</Link>
</div>
)
}
} */
] ]
return ( return (
<div className={classes.tableWrapper}> <div className="flex flex-col flex-1 mb-20">
<DataTable <DataTable
loading={loading} loading={loading}
name="cashboxHistory" name="cashboxHistory"

View file

@ -1,143 +1,61 @@
import Grid from '@mui/material/Grid'
import { makeStyles } from '@mui/styles'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import React from 'react' import React from 'react'
// import { Status } from 'src/components/Status'
// import LinkIcon from 'src/styling/icons/button/link/zodiac.svg?react'
import MachineActions from 'src/components/machineActions/MachineActions' import MachineActions from 'src/components/machineActions/MachineActions'
import { Label1 } from 'src/components/typography/index.jsx'
import { modelPrettifier } from 'src/utils/machine' import { modelPrettifier } from 'src/utils/machine'
import { formatDate } from 'src/utils/timezones' import { formatDate } from 'src/utils/timezones'
import { labelStyles, machineDetailsStyles } from './MachineDetailsCard.styles'
// const supportArtices = [
// {
// // Default article for non-maped statuses
// code: undefined,
// label: 'Troubleshooting',
// article:
// 'https://support.lamassu.is/hc/en-us/categories/115000075249-Troubleshooting'
// }
// // TODO add Stuck and Fully Functional statuses articles for the new-admins
// ]
// const article = ({ code: status }) =>
// supportArtices.find(({ code: article }) => article === status)
const useLStyles = makeStyles(labelStyles)
const Label = ({ children }) => { const Label = ({ children }) => {
const classes = useLStyles() return <Label1 className="text-comet mb-1">{children}</Label1>
return <div className={classes.label}>{children}</div>
} }
const useMDStyles = makeStyles(machineDetailsStyles)
const Container = ({ children, ...props }) => (
<Grid container spacing={4} {...props}>
{children}
</Grid>
)
const Item = ({ children, ...props }) => (
<Grid item xs {...props}>
{children}
</Grid>
)
const MachineDetailsRow = ({ it: machine, onActionSuccess, timezone }) => { const MachineDetailsRow = ({ it: machine, onActionSuccess, timezone }) => {
const classes = useMDStyles()
return ( return (
<Container className={classes.wrapper}> <div className="flex flex-wrap mt-3 mb-4 text-sm">
{/* <Item xs={5}> <div className="w-1/4">
<Container> <Label>Machine model</Label>
<Item> <span>{modelPrettifier[machine.model]}</span>
<Label>Statuses</Label> </div>
<ul className={classes.list}> <div className="w-1/4">
{machine.statuses.map((status, index) => ( <Label>Paired at</Label>
<li className={classes.item} key={index}> <span>
<Status status={status} /> {timezone &&
</li> formatDate(machine.pairedAt, timezone, 'yyyy-MM-dd HH:mm:ss')}
))} </span>
</ul> </div>
</Item> <div className="w-1/2 flex-1/2">
<Item> <MachineActions
<Label>Lamassu Support article</Label> machine={machine}
<ul className={classes.list}> onActionSuccess={onActionSuccess}></MachineActions>
{machine.statuses </div>
.map(article) <div className="w-1/6">
.map(({ label, article }, index) => ( <Label>Network speed</Label>
<li className={classes.item} key={index}> <span>
<a {machine.downloadSpeed
className={classes.link} ? new BigNumber(machine.downloadSpeed).toFixed(4).toString() +
target="_blank" ' MB/s'
rel="noopener noreferrer" : 'unavailable'}
href={article}> </span>
'{label}' <LinkIcon /> </div>
</a> <div className="w-1/6">
</li> <Label>Latency</Label>
))} <span>
</ul> {machine.responseTime
</Item> ? new BigNumber(machine.responseTime).toFixed(3).toString() + ' ms'
</Container> : 'unavailable'}
</Item> </span>
<Divider </div>
orientation="vertical" <div className="w-1/6">
flexItem <Label>Packet loss</Label>
className={classes.separator} <span>
/> */} {machine.packetLoss
<Item xs> ? new BigNumber(machine.packetLoss).toFixed(3).toString() + ' %'
<Container className={classes.row}> : 'unavailable'}
<Item xs={2}> </span>
<Label>Machine model</Label> </div>
<span>{modelPrettifier[machine.model]}</span> </div>
</Item>
<Item xs={4}>
<Label>Paired at</Label>
<span>
{timezone &&
formatDate(machine.pairedAt, timezone, 'yyyy-MM-dd HH:mm:ss')}
</span>
</Item>
<Item xs={6}>
<MachineActions
machine={machine}
onActionSuccess={onActionSuccess}></MachineActions>
</Item>
<Item xs={2}>
<Label>Network speed</Label>
<span>
{machine.downloadSpeed
? new BigNumber(machine.downloadSpeed).toFixed(4).toString() +
' MB/s'
: 'unavailable'}
</span>
</Item>
<Item xs={2}>
<Label>Latency</Label>
<span>
{machine.responseTime
? new BigNumber(machine.responseTime).toFixed(3).toString() +
' ms'
: 'unavailable'}
</span>
</Item>
<Item xs={2}>
<Label>Packet loss</Label>
<span>
{machine.packetLoss
? new BigNumber(machine.packetLoss).toFixed(3).toString() +
' %'
: 'unavailable'}
</span>
</Item>
</Container>
</Item>
</Container>
) )
} }

View file

@ -1,47 +0,0 @@
import { alpha } from '@mui/material/styles'
import {
detailsRowStyles,
labelStyles
} from 'src/pages/Transactions/Transactions.styles'
import { spacer, comet, primaryColor, fontSize4 } from 'src/styling/variables'
const machineDetailsStyles = {
...detailsRowStyles,
wrapper: {
display: 'flex',
// marginTop: 24,
// marginBottom: 32,
marginTop: 12,
marginBottom: 16,
fontSize: fontSize4
},
row: {
display: 'flex',
flexDirection: 'row'
// marginBottom: 36
},
list: {
padding: 0,
margin: 0,
listStyle: 'none'
},
item: {
height: spacer * 3,
marginBottom: spacer * 1.5
},
link: {
color: primaryColor,
textDecoration: 'none'
},
separator: {
width: 1,
height: 170,
zIndex: 1,
marginRight: 60,
marginLeft: 'auto',
background: alpha(comet, 0.5)
}
}
export { labelStyles, machineDetailsStyles }

View file

@ -1,5 +1,4 @@
import { useQuery, gql } from "@apollo/client"; import { useQuery, gql } from '@apollo/client'
import { makeStyles } from '@mui/styles'
import { formatDistance } from 'date-fns' import { formatDistance } from 'date-fns'
import * as R from 'ramda' import * as R from 'ramda'
import React from 'react' import React from 'react'
@ -7,12 +6,11 @@ import { useHistory, useLocation } from 'react-router-dom'
import { MainStatus } from 'src/components/Status' import { MainStatus } from 'src/components/Status'
import Title from 'src/components/Title' import Title from 'src/components/Title'
import DataTable from 'src/components/tables/DataTable' import DataTable from 'src/components/tables/DataTable'
import { Label1 } from 'src/components/typography/index.jsx'
import MachineRedirectIcon from 'src/styling/icons/month arrows/right.svg?react' import MachineRedirectIcon from 'src/styling/icons/month arrows/right.svg?react'
import WarningIcon from 'src/styling/icons/status/pumpkin.svg?react' import WarningIcon from 'src/styling/icons/status/pumpkin.svg?react'
import ErrorIcon from 'src/styling/icons/status/tomato.svg?react' import ErrorIcon from 'src/styling/icons/status/tomato.svg?react'
import { mainStyles } from 'src/pages/Transactions/Transactions.styles'
import MachineDetailsRow from './MachineDetailsCard' import MachineDetailsRow from './MachineDetailsCard'
const GET_MACHINES = gql` const GET_MACHINES = gql`
@ -56,10 +54,7 @@ const GET_DATA = gql`
} }
` `
const useStyles = makeStyles(mainStyles)
const MachineStatus = () => { const MachineStatus = () => {
const classes = useStyles()
const history = useHistory() const history = useHistory()
const { state } = useLocation() const { state } = useLocation()
const addedMachineId = state?.id const addedMachineId = state?.id
@ -78,10 +73,9 @@ const MachineStatus = () => {
size: 'sm', size: 'sm',
textAlign: 'left', textAlign: 'left',
view: m => ( view: m => (
<div className={classes.flexRow}> <div className="flex items-center gap-2">
{m.name} {m.name}
<div <div
className={classes.machineRedirectContainer}
onClick={() => { onClick={() => {
history.push(`/machines/${m.deviceId}`) history.push(`/machines/${m.deviceId}`)
}}> }}>
@ -131,18 +125,16 @@ const MachineStatus = () => {
return ( return (
<> <>
<div className={classes.titleWrapper}> <div className="flex justify-between items-center">
<div className={classes.titleAndButtonsContainer}> <Title>Machine status</Title>
<Title>Machine status</Title> <div className="flex gap-6">
</div> <div className="flex items-center gap-2">
<div className={classes.headerLabels}>
<div>
<WarningIcon /> <WarningIcon />
<span>Warning</span> <Label1 noMargin>Warning</Label1>
</div> </div>
<div> <div className="flex items-center gap-2">
<ErrorIcon /> <ErrorIcon />
<span>Error</span> <Label1 noMargin>Error</Label1>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,77 +1,35 @@
import { makeStyles } from '@mui/styles'
import React from 'react' import React from 'react'
import { H1, P, Info2 } from 'src/components/typography' import { H1, P, Info2 } from 'src/components/typography'
import WarningIcon from 'src/styling/icons/warning-icon/comet.svg?react' import WarningIcon from 'src/styling/icons/warning-icon/comet.svg?react'
import { Button } from 'src/components/buttons' import { Button } from 'src/components/buttons'
import filledCassettes from 'src/styling/icons/cassettes/both-filled.svg' import filledCassettes from 'src/styling/icons/cassettes/both-filled.svg'
import { comet } from 'src/styling/variables'
const styles = {
button: {
margin: [[35, 'auto', 0, 'auto']]
},
modalContent: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
flex: 1,
padding: [[0, 34]]
},
splashTitle: {
marginTop: 15
},
warningInfo: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
marginTop: 15
},
warningIcon: {
width: 25,
height: 25,
marginRight: 8,
display: 'block'
},
warningText: {
flexBasis: '100%',
flexGrow: 1
},
machineName: {
margin: [[5, 0]],
color: comet
}
}
const useStyles = makeStyles(styles)
const WizardSplash = ({ name, onContinue }) => { const WizardSplash = ({ name, onContinue }) => {
const classes = useStyles()
return ( return (
<div className={classes.modalContent}> <div className="flex flex-col items-center flex-1 pt-0 pb-12 px-8 gap-4">
<img width="148" height="196" alt="cassette" src={filledCassettes}></img> <img width="148" height="196" alt="cassette" src={filledCassettes}></img>
<H1 className={classes.splashTitle} noMargin> <div className="flex flex-col items-center">
Update counts <H1 noMargin>Update counts</H1>
</H1> <Info2 noMargin className="text-comet my-1">
<Info2 className={classes.machineName} noMargin> {name}
{name} </Info2>
</Info2> </div>
<div className={classes.warningInfo}> <div className="flex items-center gap-2">
<WarningIcon className={classes.warningIcon} /> <WarningIcon className="h-6 w-6" />
<P noMargin className={classes.warningText}> <P noMargin className="flex-1">
Before updating counts on Lamassu Admin, make sure you've done it Before updating counts on Lamassu Admin, make sure you've done it
before on the machines. before on the machines.
</P> </P>
</div> </div>
<div className={classes.warningInfo}> <div className="flex items-center gap-2">
<WarningIcon className={classes.warningIcon} /> <WarningIcon className="h-6 w-6" />
<P noMargin className={classes.warningText}> <P noMargin className="flex-1">
For cash cassettes, please make sure you've removed the remaining For cash cassettes, please make sure you've removed the remaining
bills before adding the new ones. bills before adding the new ones.
</P> </P>
</div> </div>
<Button className={classes.button} onClick={onContinue}> <Button className="m-auto mb-0" onClick={onContinue}>
Get started Get started
</Button> </Button>
</div> </div>

View file

@ -1,4 +1,3 @@
import { makeStyles } from '@mui/styles'
import classnames from 'classnames' import classnames from 'classnames'
import { Formik, Form, Field } from 'formik' import { Formik, Form, Field } from 'formik'
import * as R from 'ramda' import * as R from 'ramda'
@ -22,89 +21,10 @@ import tejo4CassetteOne from 'src/styling/icons/cassettes/tejo/4-cassettes/4-cas
import tejo4CassetteTwo from 'src/styling/icons/cassettes/tejo/4-cassettes/4-cassettes-open-2-left.svg' import tejo4CassetteTwo from 'src/styling/icons/cassettes/tejo/4-cassettes/4-cassettes-open-2-left.svg'
import tejo4CassetteThree from 'src/styling/icons/cassettes/tejo/4-cassettes/4-cassettes-open-3-left.svg' import tejo4CassetteThree from 'src/styling/icons/cassettes/tejo/4-cassettes/4-cassettes-open-3-left.svg'
import tejo4CassetteFour from 'src/styling/icons/cassettes/tejo/4-cassettes/4-cassettes-open-4-left.svg' import tejo4CassetteFour from 'src/styling/icons/cassettes/tejo/4-cassettes/4-cassettes-open-4-left.svg'
import { comet, errorColor } from 'src/styling/variables'
import { getCashUnitCapacity } from 'src/utils/machine' import { getCashUnitCapacity } from 'src/utils/machine'
import { numberToFiatAmount } from 'src/utils/number' import { numberToFiatAmount } from 'src/utils/number'
import { startCase } from 'src/utils/string' import { startCase } from 'src/utils/string'
import classes from './WizardStep.module.css'
const styles = {
content: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
flex: 1,
paddingBottom: 32
},
titleDiv: {
marginBottom: 32
},
title: {
margin: [[0, 0, 12, 0]],
color: comet
},
stepImage: {
width: 148,
height: 196
},
form: {
paddingBottom: 95
},
verticalAlign: {
display: 'flex',
flexDirection: 'column'
},
horizontalAlign: {
display: 'flex',
flexDirection: 'row'
},
centerAlignment: {
alignItems: 'center'
},
lineAlignment: {
alignItems: 'baseline'
},
fullWidth: {
margin: [[0, 'auto']],
flexBasis: 'auto'
},
formWrapper: {
flexBasis: '100%',
display: 'flex',
justifyContent: 'center'
},
submit: {
float: 'right'
},
cashboxBills: {
marginRight: 5
},
cassetteCashbox: {
width: 40,
height: 35
},
cassetteFormTitle: {
marginTop: 18
},
cassetteFormTitleContent: {
marginLeft: 10,
marginRight: 25
},
smBottomMargin: {
marginBottom: 25
},
fiatTotal: {
color: comet
},
errorMessage: {
color: errorColor
},
stepErrorMessage: {
maxWidth: 275,
marginTop: 25
}
}
const useStyles = makeStyles(styles)
const CASHBOX_STEP = 1 const CASHBOX_STEP = 1
@ -171,8 +91,6 @@ const WizardStep = ({
onContinue, onContinue,
initialValues initialValues
}) => { }) => {
const classes = useStyles()
const label = lastStep ? 'Finish' : 'Confirm' const label = lastStep ? 'Finish' : 'Confirm'
const stepOneRadioOptions = [ const stepOneRadioOptions = [
@ -197,9 +115,11 @@ const WizardStep = ({
) )
return ( return (
<div className={classes.content}> <div className="flex flex-col flex-1 pb-6 gap-6">
<div className={classes.titleDiv}> <div className="mb-4">
<Info2 className={classes.title}>{name}</Info2> <Info2 noMargin className="mb-3">
{name}
</Info2>
<Stepper steps={steps.length} currentStep={step} /> <Stepper steps={steps.length} currentStep={step} />
</div> </div>
@ -212,19 +132,14 @@ const WizardStep = ({
enableReinitialize enableReinitialize
validationSchema={steps[0].schema}> validationSchema={steps[0].schema}>
{({ errors }) => ( {({ errors }) => (
<Form> <Form className="flex flex-col flex-1">
<div <div className="flex flex-row pb-25">
className={classnames(classes.horizontalAlign, classes.form)}>
<img <img
className={classes.stepImage} className={classes.stepImage}
alt={cashUnitCategory} alt={cashUnitCategory}
src={cashbox}></img> src={cashbox}></img>
<div className={classes.formWrapper}> <div className={classes.formWrapper}>
<div <div className={classes.verticalAlign}>
className={classnames(
classes.verticalAlign,
classes.fullWidth
)}>
<H4 noMargin>Did you empty the cash box?</H4> <H4 noMargin>Did you empty the cash box?</H4>
<Field <Field
component={RadioGroup} component={RadioGroup}
@ -233,14 +148,14 @@ const WizardStep = ({
className={classes.horizontalAlign} className={classes.horizontalAlign}
/> />
{errors.wasCashboxEmptied && ( {errors.wasCashboxEmptied && (
<div className={classes.errorMessage}> <div className="text-tomato">
{errors.wasCashboxEmptied} {errors.wasCashboxEmptied}
</div> </div>
)} )}
<div <div
className={classnames( className={classnames(
classes.horizontalAlign, classes.horizontalAlign,
classes.centerAlignment 'items-center'
)}> )}>
<P>Since previous update</P> <P>Since previous update</P>
<HelpTooltip width={215}> <HelpTooltip width={215}>
@ -253,9 +168,9 @@ const WizardStep = ({
<div <div
className={classnames( className={classnames(
classes.horizontalAlign, classes.horizontalAlign,
classes.lineAlignment 'items-baseline'
)}> )}>
<Info1 noMargin className={classes.cashboxBills}> <Info1 noMargin className="mr-1">
{machine?.cashUnits.cashbox} {machine?.cashUnits.cashbox}
</Info1> </Info1>
<P noMargin>accepted bills</P> <P noMargin>accepted bills</P>
@ -263,7 +178,7 @@ const WizardStep = ({
</div> </div>
</div> </div>
</div> </div>
<Button className={classes.submit} type="submit"> <Button className="mt-auto ml-auto" type="submit">
{label} {label}
</Button> </Button>
</Form> </Form>
@ -280,9 +195,8 @@ const WizardStep = ({
enableReinitialize enableReinitialize
validationSchema={steps[step - 1].schema}> validationSchema={steps[step - 1].schema}>
{({ values, errors }) => ( {({ values, errors }) => (
<Form> <Form className="flex flex-col flex-1">
<div <div className={classnames(classes.horizontalAlign, 'pb-6')}>
className={classnames(classes.horizontalAlign, classes.form)}>
<img <img
className={classes.stepImage} className={classes.stepImage}
alt={cashUnitCategory} alt={cashUnitCategory}
@ -292,25 +206,13 @@ const WizardStep = ({
numberOfRecyclers numberOfRecyclers
)}></img> )}></img>
<div className={classes.formWrapper}> <div className={classes.formWrapper}>
<div <div className={classes.verticalAlign}>
className={classnames(
classes.verticalAlign,
classes.fullWidth
)}>
<div <div
className={classnames( className={classnames(classes.horizontalAlign, 'mb-6')}>
classes.horizontalAlign,
classes.smBottomMargin
)}>
<div <div
className={classnames( className={classnames(classes.horizontalAlign, 'mt-4')}>
classes.horizontalAlign,
classes.cassetteFormTitle
)}>
<TxOutIcon /> <TxOutIcon />
<H4 <H4 className="ml-2 mr-6" noMargin>
className={classes.cassetteFormTitleContent}
noMargin>
{startCase(cashUnitField)} ( {startCase(cashUnitField)} (
{cashUnitCategory === 'cassette' {cashUnitCategory === 'cassette'
? `dispenser` ? `dispenser`
@ -321,7 +223,7 @@ const WizardStep = ({
</H4> </H4>
</div> </div>
<Cashbox <Cashbox
className={classes.cassetteCashbox} className="h-10 w-9"
percent={getPercentage(values)} percent={getPercentage(values)}
cashOut cashOut
/> />
@ -330,7 +232,7 @@ const WizardStep = ({
<div <div
className={classnames( className={classnames(
classes.horizontalAlign, classes.horizontalAlign,
classes.lineAlignment 'items-baseline'
)}> )}>
<Field <Field
component={NumberInput} component={NumberInput}
@ -338,26 +240,26 @@ const WizardStep = ({
width={50} width={50}
placeholder={originalCashUnitCount.toString()} placeholder={originalCashUnitCount.toString()}
name={cashUnitField} name={cashUnitField}
className={classes.cashboxBills} className="mr-1"
autoFocus autoFocus
/> />
<P> <P>
{cashUnitDenomination} {fiatCurrency} bills loaded {cashUnitDenomination} {fiatCurrency} bills loaded
</P> </P>
</div> </div>
<P noMargin className={classes.fiatTotal}> <P noMargin className="text-comet">
= {numberToFiatAmount(cassetteTotal(values))}{' '} = {numberToFiatAmount(cassetteTotal(values))}{' '}
{fiatCurrency} {fiatCurrency}
</P> </P>
{!R.isEmpty(errors) && ( {!R.isEmpty(errors) && (
<ErrorMessage className={classes.stepErrorMessage}> <ErrorMessage className="max-w-68 mt-6">
{R.head(R.values(errors))} {R.head(R.values(errors))}
</ErrorMessage> </ErrorMessage>
)} )}
</div> </div>
</div> </div>
</div> </div>
<Button className={classes.submit} type="submit"> <Button className="ml-auto mt-auto" type="submit">
{label} {label}
</Button> </Button>
</Form> </Form>

View file

@ -0,0 +1,22 @@
.stepImage {
width: 148px;
height: 196px;
}
.formWrapper {
flex-basis: 100%;
display: flex;
justify-content: center;
}
.verticalAlign {
display: flex;
flex-direction: column;
margin: 0 auto;
flex-basis: auto;
}
.horizontalAlign {
display: flex;
flex-direction: row;
}