feat: reuse the cash cassettes page components for the machine profile instead of duplicated code

This commit is contained in:
Sérgio Salgado 2023-05-30 14:59:02 +01:00
parent 6474017563
commit e55ebd5d84
6 changed files with 96 additions and 187 deletions

View file

@ -81,7 +81,7 @@ const Row = ({
)} )}
</Tr> </Tr>
</div> </div>
{expandable && expanded && ( {expanded && (
<div className={classes.after}> <div className={classes.after}>
<Tr className={classnames({ [classes.expanded]: expanded })}> <Tr className={classnames({ [classes.expanded]: expanded })}>
<Td width={width}> <Td width={width}>
@ -99,6 +99,7 @@ const DataTable = ({
data = [], data = [],
Details, Details,
className, className,
tableClassName,
expandable, expandable,
initialExpanded, initialExpanded,
onClick, onClick,
@ -169,7 +170,7 @@ const DataTable = ({
return ( return (
<Box display="flex" flex="1" flexDirection="column"> <Box display="flex" flex="1" flexDirection="column">
<Table className={classes.table}> <Table className={classnames(classes.table, tableClassName)}>
<THead> <THead>
{elements.map(({ width, className, textAlign, header }, idx) => ( {elements.map(({ width, className, textAlign, header }, idx) => (
<Th <Th

View file

@ -3,92 +3,17 @@ import { makeStyles } from '@material-ui/core'
import gql from 'graphql-tag' 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 * as Yup from 'yup'
import { IconButton } from 'src/components/buttons' import DataTable from 'src/components/tables/DataTable'
import { Table as EditableTable } from 'src/components/editableTable' import CashUnitDetails from 'src/pages/Maintenance/CashUnitDetails'
import { CashOut, CashIn } from 'src/components/inputs/cashbox/Cashbox'
import { NumberInput, CashCassetteInput } from 'src/components/inputs/formik'
import Wizard from 'src/pages/Maintenance/Wizard/Wizard' import Wizard from 'src/pages/Maintenance/Wizard/Wizard'
import { ReactComponent as EditIcon } from 'src/styling/icons/action/edit/enabled.svg' import helper from 'src/pages/Maintenance/helper'
import { fromNamespace } from 'src/utils/config' import { fromNamespace } from 'src/utils/config'
import styles from './Cassettes.styles' import styles from './Cassettes.styles'
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
const widthsByNumberOfCassettes = {
2: { cashbox: 203, cassette: 280, cassetteGraph: 80, editWidth: 87 },
3: { cashbox: 164, cassette: 200, cassetteGraph: 60, editWidth: 87 },
4: { cashbox: 131, cassette: 158, cassetteGraph: 40, editWidth: 87 }
}
const ValidationSchema = Yup.object().shape({
name: Yup.string().required('Required'),
cashbox: Yup.number()
.label('Cash box')
.required()
.integer()
.min(0)
.max(1000),
cassette1: Yup.number()
.required('Required')
.integer()
.min(0)
.max(500),
cassette2: Yup.number()
.required('Required')
.integer()
.min(0)
.max(500),
cassette3: Yup.number()
.required('Required')
.integer()
.min(0)
.max(500),
cassette4: Yup.number()
.required('Required')
.integer()
.min(0)
.max(500),
stacker1f: Yup.number()
.label('Stacker 1F')
.required('Required')
.integer()
.min(0)
.max(40),
stacker1r: Yup.number()
.label('Stacker 1R')
.required('Required')
.integer()
.min(0)
.max(60),
stacker2f: Yup.number()
.label('Stacker 2F')
.required('Required')
.integer()
.min(0)
.max(60),
stacker2r: Yup.number()
.label('Stacker 2R')
.required('Required')
.integer()
.min(0)
.max(60),
stacker3f: Yup.number()
.label('Stacker 3F')
.required('Required')
.integer()
.min(0)
.max(60),
stacker3r: Yup.number()
.label('Stacker 3R')
.required('Required')
.integer()
.min(0)
.max(60)
})
const SET_CASSETTE_BILLS = gql` const SET_CASSETTE_BILLS = gql`
mutation MachineAction( mutation MachineAction(
$deviceId: ID! $deviceId: ID!
@ -114,6 +39,13 @@ const SET_CASSETTE_BILLS = gql`
} }
` `
const widths = {
name: 0,
cashbox: 175,
cassettes: 585,
edit: 90
}
const CashCassettes = ({ machine, config, refetchData, bills }) => { const CashCassettes = ({ machine, config, refetchData, bills }) => {
const classes = useStyles() const classes = useStyles()
@ -121,89 +53,14 @@ const CashCassettes = ({ machine, config, refetchData, bills }) => {
const cashout = config && fromNamespace('cashOut')(config) const cashout = config && fromNamespace('cashOut')(config)
const locale = config && fromNamespace('locale')(config) const locale = config && fromNamespace('locale')(config)
const fillingPercentageSettings =
config && fromNamespace('notifications', config)
const fiatCurrency = locale?.fiatCurrency const fiatCurrency = locale?.fiatCurrency
const numberOfCassettes = machine.numberOfCassettes
const getCashoutSettings = deviceId => fromNamespace(deviceId)(cashout) const getCashoutSettings = deviceId => fromNamespace(deviceId)(cashout)
const isCashOutDisabled = ({ deviceId }) =>
!getCashoutSettings(deviceId).active
const elements = [ const elements = R.filter(it => it.name !== 'name')(
{ helper.getElements(classes, config, bills, setWizard, widths)
name: 'cashbox',
header: 'Cash box',
width: widthsByNumberOfCassettes[numberOfCassettes].cashbox,
stripe: false,
view: value => (
<CashIn
currency={{ code: fiatCurrency }}
notes={value}
total={R.sum(R.map(it => it.fiat)(bills))}
/>
),
input: NumberInput,
inputProps: {
decimalPlaces: 0
}
}
]
R.until(
R.gt(R.__, numberOfCassettes),
it => {
elements.push({
name: `cassette${it}`,
header: `Cash cassette ${it}`,
width: widthsByNumberOfCassettes[numberOfCassettes].cassette,
stripe: true,
doubleHeader: 'Cash-out',
view: value => {
return (
<CashOut
className={classes.cashbox}
denomination={
getCashoutSettings(machine.deviceId)?.[`cassette${it}`]
}
currency={{ code: fiatCurrency }}
notes={value}
width={widthsByNumberOfCassettes[numberOfCassettes].cassetteGraph}
threshold={
fillingPercentageSettings[`fillingPercentageCassette${it}`]
}
/>
)
},
isHidden: ({ numberOfCassettes }) => it > numberOfCassettes,
input: CashCassetteInput,
inputProps: {
decimalPlaces: 0,
width: widthsByNumberOfCassettes[numberOfCassettes].cassetteGraph,
inputClassName: classes.cashbox
}
})
return R.add(1, it)
},
1
) )
elements.push({
name: 'edit',
header: 'Edit',
width: widthsByNumberOfCassettes[numberOfCassettes].editWidth,
view: () => {
return (
<IconButton
onClick={() => {
setWizard(true)
}}>
<EditIcon />
</IconButton>
)
}
})
const [setCassetteBills, { error }] = useMutation(SET_CASSETTE_BILLS, { const [setCassetteBills, { error }] = useMutation(SET_CASSETTE_BILLS, {
refetchQueries: () => refetchData() refetchQueries: () => refetchData()
}) })
@ -218,18 +75,26 @@ const CashCassettes = ({ machine, config, refetchData, bills }) => {
} }
}) })
const InnerCashUnitDetails = ({ it }) => (
<CashUnitDetails
machine={it}
bills={bills[it.id] ?? []}
currency={fiatCurrency}
config={config}
hideMachineData
widths
/>
)
return machine.name ? ( return machine.name ? (
<> <>
<EditableTable <DataTable
error={error?.message}
editWidth={widthsByNumberOfCassettes[numberOfCassettes].editWidth}
stripeWhen={isCashOutDisabled}
disableRowEdit={isCashOutDisabled}
name="cashboxes"
elements={elements} elements={elements}
data={[machine]} data={[machine]}
save={onSave} Details={InnerCashUnitDetails}
validationSchema={ValidationSchema} emptyText="No machines so far"
initialExpanded={0}
tableClassName={classes.dataTable}
/> />
{wizard && ( {wizard && (
<Wizard <Wizard

View file

@ -1,6 +1,34 @@
import { offDarkColor } from 'src/styling/variables'
const styles = { const styles = {
cashbox: { unitsRow: {
height: 36 display: 'flex',
flexDirection: 'row',
margin: [[10, 0]],
'& > *': {
marginRight: 30
},
'& > *:last-child': {
marginRight: 0
}
},
units: {
display: 'flex',
flexDirection: 'row',
'& > *': {
marginRight: 10
},
'& > *:last-child': {
marginRight: 0
}
},
verticalLine: {
height: '100%',
width: 1,
backgroundColor: offDarkColor
},
dataTable: {
minHeight: 290
} }
} }

View file

@ -36,10 +36,10 @@ const styles = {
flexDirection: 'column', flexDirection: 'column',
minWidth: 210 minWidth: 210
}, },
billList: { billList: ({ hideMachineData }) => ({
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
minWidth: 160, minWidth: hideMachineData ? 80 : 160,
'& > span': { '& > span': {
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
@ -48,7 +48,7 @@ const styles = {
minWidth: 30 minWidth: 30
} }
} }
}, }),
unitList: { unitList: {
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
@ -82,8 +82,14 @@ const styles = {
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
const CashUnitDetails = ({ machine, bills, currency, config }) => { const CashUnitDetails = ({
const classes = useStyles() machine,
bills,
currency,
config,
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)
@ -91,10 +97,12 @@ const CashUnitDetails = ({ machine, bills, currency, config }) => {
return ( return (
<div className={classes.wrapper}> <div className={classes.wrapper}>
<div className={classes.machineData}> {!hideMachineData && (
<Label1>Machine Model</Label1> <div className={classes.machineData}>
<span>{modelPrettifier[machine.model]}</span> <Label1>Machine Model</Label1>
</div> <span>{modelPrettifier[machine.model]}</span>
</div>
)}
<div className={classes.billList}> <div className={classes.billList}>
<Label1>Cash box</Label1> <Label1>Cash box</Label1>
{R.isEmpty(billCount) && <TL2 noMargin>Empty</TL2>} {R.isEmpty(billCount) && <TL2 noMargin>Empty</TL2>}

View file

@ -101,6 +101,13 @@ const GET_BATCHES_CSV = gql`
} }
` `
const widths = {
name: 250,
cashbox: 200,
cassettes: 575,
edit: 90
}
const CashCassettes = () => { const CashCassettes = () => {
const classes = useStyles() const classes = useStyles()
const [showHistory, setShowHistory] = useState(false) const [showHistory, setShowHistory] = useState(false)
@ -176,12 +183,12 @@ const CashCassettes = () => {
} }
const elements = helper.getElements( const elements = helper.getElements(
machines,
classes, classes,
config, config,
bills, bills,
setMachineId, setWizard,
setWizard widths,
setMachineId
) )
const InnerCashUnitDetails = ({ it }) => ( const InnerCashUnitDetails = ({ it }) => (

View file

@ -7,12 +7,12 @@ import { fromNamespace } from 'src/utils/config'
import { cashUnitCapacity } from 'src/utils/machine' import { cashUnitCapacity } from 'src/utils/machine'
const getElements = ( const getElements = (
machines,
classes, classes,
config, config,
bills, bills,
setMachineId, setWizard,
setWizard widths,
setMachineId
) => { ) => {
const fillingPercentageSettings = fromNamespace('notifications', config) const fillingPercentageSettings = fromNamespace('notifications', config)
const locale = fromNamespace('locale')(config) const locale = fromNamespace('locale')(config)
@ -25,14 +25,14 @@ const getElements = (
{ {
name: 'name', name: 'name',
header: 'Machine', header: 'Machine',
width: 250, width: widths.name,
view: m => <>{m.name}</>, view: m => <>{m.name}</>,
input: ({ field: { value: name } }) => <>{name}</> input: ({ field: { value: name } }) => <>{name}</>
}, },
{ {
name: 'cashbox', name: 'cashbox',
header: 'Cashbox', header: 'Cashbox',
width: 200, width: widths.cashbox,
view: m => ( view: m => (
<CashIn <CashIn
currency={{ code: fiatCurrency }} currency={{ code: fiatCurrency }}
@ -51,7 +51,7 @@ const getElements = (
{ {
name: 'cassettes', name: 'cassettes',
header: 'Cassettes & Recyclers', header: 'Cassettes & Recyclers',
width: 575, width: widths.cassettes,
view: m => { view: m => {
return ( return (
<div className={classes.unitsRow}> <div className={classes.unitsRow}>
@ -112,13 +112,13 @@ const getElements = (
{ {
name: 'edit', name: 'edit',
header: 'Edit', header: 'Edit',
width: 90, width: widths.edit,
textAlign: 'center', textAlign: 'center',
view: m => { view: m => {
return ( return (
<IconButton <IconButton
onClick={() => { onClick={() => {
setMachineId(m.id) !R.isNil(setMachineId) && setMachineId(m.id)
setWizard(true) setWizard(true)
}}> }}>
<EditIcon /> <EditIcon />