Merge pull request #373 from mautematico/feat-add-cashboxes-screen
feat: add cashboxes screen
This commit is contained in:
commit
d7ff61d83f
11 changed files with 500 additions and 8 deletions
|
|
@ -75,6 +75,11 @@ function resetCashOutBills (rec) {
|
||||||
return db.none(sql, [rec.cassettes[0], rec.cassettes[1], rec.deviceId])
|
return db.none(sql, [rec.cassettes[0], rec.cassettes[1], rec.deviceId])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function emptyCashInBills (rec) {
|
||||||
|
const sql = 'update devices set cashbox=0 where device_id=$1'
|
||||||
|
return db.none(sql, [rec.deviceId])
|
||||||
|
}
|
||||||
|
|
||||||
function unpair (rec) {
|
function unpair (rec) {
|
||||||
return pairing.unpair(rec.deviceId)
|
return pairing.unpair(rec.deviceId)
|
||||||
}
|
}
|
||||||
|
|
@ -89,6 +94,7 @@ function restartServices (rec) {
|
||||||
|
|
||||||
function setMachine (rec) {
|
function setMachine (rec) {
|
||||||
switch (rec.action) {
|
switch (rec.action) {
|
||||||
|
case 'emptyCashInBills': return emptyCashInBills(rec)
|
||||||
case 'resetCashOutBills': return resetCashOutBills(rec)
|
case 'resetCashOutBills': return resetCashOutBills(rec)
|
||||||
case 'unpair': return unpair(rec)
|
case 'unpair': return unpair(rec)
|
||||||
case 'reboot': return reboot(rec)
|
case 'reboot': return reboot(rec)
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,7 @@ const typeDefs = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MachineAction {
|
enum MachineAction {
|
||||||
|
emptyCashInBills
|
||||||
resetCashOutBills
|
resetCashOutBills
|
||||||
unpair
|
unpair
|
||||||
reboot
|
reboot
|
||||||
|
|
@ -214,7 +215,7 @@ const typeDefs = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
machineAction(deviceId:ID!, action: MachineAction!): Machine
|
machineAction(deviceId:ID!, action: MachineAction!, cassettes: [Int]): Machine
|
||||||
machineSupportLogs(deviceId: ID!): SupportLogsResponse
|
machineSupportLogs(deviceId: ID!): SupportLogsResponse
|
||||||
serverSupportLogs: SupportLogsResponse
|
serverSupportLogs: SupportLogsResponse
|
||||||
setCustomer(customerId: ID!, customerInput: CustomerInput): Customer
|
setCustomer(customerId: ID!, customerInput: CustomerInput): Customer
|
||||||
|
|
@ -254,7 +255,7 @@ const resolvers = {
|
||||||
accounts: () => settingsLoader.getAccounts()
|
accounts: () => settingsLoader.getAccounts()
|
||||||
},
|
},
|
||||||
Mutation: {
|
Mutation: {
|
||||||
machineAction: (...[, { deviceId, action }]) => machineAction({ deviceId, action }),
|
machineAction: (...[, { deviceId, action, cassettes }]) => machineAction({ deviceId, action, cassettes }),
|
||||||
machineSupportLogs: (...[, { deviceId }]) => supportLogs.insert(deviceId),
|
machineSupportLogs: (...[, { deviceId }]) => supportLogs.insert(deviceId),
|
||||||
createPairingTotem: (...[, { name }]) => pairing.totem(name),
|
createPairingTotem: (...[, { name }]) => pairing.totem(name),
|
||||||
serverSupportLogs: () => serverLogs.insert(),
|
serverSupportLogs: () => serverLogs.insert(),
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,13 @@ function getMachine (machineId) {
|
||||||
.then(machines => machines.find(({ deviceId }) => deviceId === machineId))
|
.then(machines => machines.find(({ deviceId }) => deviceId === machineId))
|
||||||
}
|
}
|
||||||
|
|
||||||
function machineAction ({ deviceId, action }) {
|
function machineAction ({ deviceId, action, cassettes }) {
|
||||||
return getMachine(deviceId)
|
return getMachine(deviceId)
|
||||||
.then(machine => {
|
.then(machine => {
|
||||||
if (!machine) throw new UserInputError(`machine:${deviceId} not found`, { deviceId })
|
if (!machine) throw new UserInputError(`machine:${deviceId} not found`, { deviceId })
|
||||||
return machine
|
return machine
|
||||||
})
|
})
|
||||||
.then(machineLoader.setMachine({ deviceId, action }))
|
.then(machineLoader.setMachine({ deviceId, action, cassettes }))
|
||||||
.then(getMachine(deviceId))
|
.then(getMachine(deviceId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
151
new-lamassu-admin/src/components/inputs/cashbox/Cashbox.js
Normal file
151
new-lamassu-admin/src/components/inputs/cashbox/Cashbox.js
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import Chip from 'src/components/Chip'
|
||||||
|
import { Link } from 'src/components/buttons'
|
||||||
|
import { Info2, Label1, Label2 } from 'src/components/typography'
|
||||||
|
|
||||||
|
import TextInputFormik from '../base/TextInput'
|
||||||
|
|
||||||
|
import { cashboxStyles, gridStyles } from './Cashbox.styles'
|
||||||
|
|
||||||
|
const cashboxClasses = makeStyles(cashboxStyles)
|
||||||
|
const gridClasses = makeStyles(gridStyles)
|
||||||
|
|
||||||
|
const Cashbox = ({ percent = 0, cashOut = false }) => {
|
||||||
|
const classes = cashboxClasses({ percent, cashOut })
|
||||||
|
return (
|
||||||
|
<div className={classes.cashbox}>
|
||||||
|
<div className={classes.emptyPart}>
|
||||||
|
{percent <= 50 && <Label2>{percent.toFixed(0)}%</Label2>}
|
||||||
|
</div>
|
||||||
|
<div className={classes.fullPart}>
|
||||||
|
{percent > 50 && <Label2>{percent.toFixed(0)}%</Label2>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://support.lamassu.is/hc/en-us/articles/360025595552-Installing-the-Sintra-Forte
|
||||||
|
// Sintra and Sintra Forte can have up to 500 notes per cashOut box and up to 1000 per cashIn box
|
||||||
|
const CashIn = ({ capacity = 1000, notes = 0, total = 0 }) => {
|
||||||
|
const percent = (100 * notes) / capacity
|
||||||
|
const classes = gridClasses()
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={classes.row}>
|
||||||
|
<div>
|
||||||
|
<Cashbox percent={percent} />
|
||||||
|
</div>
|
||||||
|
<div className={classes.col2}>
|
||||||
|
<div>
|
||||||
|
<Info2 className={classes.noMarginText}>{notes} notes</Info2>
|
||||||
|
<Label1 className={classes.noMarginText}>{total}</Label1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CashInFormik = ({
|
||||||
|
capacity = 1000,
|
||||||
|
onEmpty,
|
||||||
|
field: {
|
||||||
|
value: { notes, deviceId }
|
||||||
|
},
|
||||||
|
form: { setFieldValue }
|
||||||
|
}) => {
|
||||||
|
const classes = gridClasses()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={classes.row}>
|
||||||
|
<div>
|
||||||
|
<Cashbox percent={(100 * notes) / capacity} />
|
||||||
|
</div>
|
||||||
|
<div className={classes.col2}>
|
||||||
|
<div>
|
||||||
|
<Link
|
||||||
|
onClick={() => {
|
||||||
|
onEmpty({
|
||||||
|
variables: {
|
||||||
|
deviceId,
|
||||||
|
action: 'emptyCashInBills'
|
||||||
|
}
|
||||||
|
}).then(() => setFieldValue('cashin.notes', 0))
|
||||||
|
}}
|
||||||
|
className={classes.link}
|
||||||
|
color={'primary'}>
|
||||||
|
Empty
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CashOut = ({ capacity = 500, denomination = 0, currency, notes }) => {
|
||||||
|
const percent = (100 * notes) / capacity
|
||||||
|
const classes = gridClasses()
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={classes.row}>
|
||||||
|
<div className={classes.col}>
|
||||||
|
<Cashbox percent={percent} cashOut />
|
||||||
|
</div>
|
||||||
|
<div className={(classes.col, classes.col2)}>
|
||||||
|
<div>
|
||||||
|
<Info2 className={classes.noMarginText}>
|
||||||
|
{notes} <Chip label={`${denomination} ${currency.code}`} />
|
||||||
|
</Info2>
|
||||||
|
<Label1 className={classes.noMarginText}>
|
||||||
|
{notes * denomination} {currency.code}
|
||||||
|
</Label1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CashOutFormik = ({ capacity = 500, ...props }) => {
|
||||||
|
const {
|
||||||
|
name,
|
||||||
|
onChange,
|
||||||
|
onBlur,
|
||||||
|
value: { notes }
|
||||||
|
} = props.field
|
||||||
|
const { touched, errors } = props.form
|
||||||
|
|
||||||
|
const error = !!(touched[name] && errors[name])
|
||||||
|
|
||||||
|
const percent = (100 * notes) / capacity
|
||||||
|
const classes = gridClasses()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={classes.row}>
|
||||||
|
<div className={classes.col}>
|
||||||
|
<Cashbox percent={percent} cashOut />
|
||||||
|
</div>
|
||||||
|
<div className={(classes.col, classes.col2)}>
|
||||||
|
<div>
|
||||||
|
<TextInputFormik
|
||||||
|
fullWidth
|
||||||
|
name={name + '.notes'}
|
||||||
|
onChange={onChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
value={notes}
|
||||||
|
error={error}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Cashbox, CashIn, CashInFormik, CashOut, CashOutFormik }
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { spacer, tomato, primaryColor as zodiac } from 'src/styling/variables'
|
||||||
|
|
||||||
|
const colors = {
|
||||||
|
cashOut: {
|
||||||
|
empty: tomato,
|
||||||
|
full: zodiac
|
||||||
|
},
|
||||||
|
cashIn: {
|
||||||
|
empty: zodiac,
|
||||||
|
full: tomato
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const colorPicker = ({ percent, cashOut }) =>
|
||||||
|
colors[cashOut ? 'cashOut' : 'cashIn'][percent >= 50 ? 'full' : 'empty']
|
||||||
|
|
||||||
|
const cashboxStyles = {
|
||||||
|
cashbox: {
|
||||||
|
borderColor: colorPicker,
|
||||||
|
backgroundColor: colorPicker,
|
||||||
|
height: 34,
|
||||||
|
width: 80,
|
||||||
|
border: '2px solid',
|
||||||
|
textAlign: 'end',
|
||||||
|
display: 'inline-block'
|
||||||
|
},
|
||||||
|
emptyPart: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
height: ({ percent }) => `${100 - percent}%`,
|
||||||
|
'& > p': {
|
||||||
|
color: colorPicker,
|
||||||
|
display: 'inline-block'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fullPart: {
|
||||||
|
backgroundColor: colorPicker,
|
||||||
|
height: ({ percent }) => `${percent}%`,
|
||||||
|
'& > p': {
|
||||||
|
color: 'white',
|
||||||
|
display: 'inline'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const gridStyles = {
|
||||||
|
row: {
|
||||||
|
height: 36,
|
||||||
|
width: 183,
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: 'repeat(2,1fr)',
|
||||||
|
gridTemplateRows: '1fr',
|
||||||
|
gridColumnGap: 18,
|
||||||
|
gridRowGap: 0
|
||||||
|
},
|
||||||
|
col2: {
|
||||||
|
width: 117
|
||||||
|
},
|
||||||
|
noMarginText: {
|
||||||
|
marginTop: 0,
|
||||||
|
marginBottom: 0
|
||||||
|
},
|
||||||
|
link: {
|
||||||
|
marginTop: spacer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { cashboxStyles, gridStyles }
|
||||||
|
|
@ -4,5 +4,15 @@ import RadioGroup from './base/RadioGroup'
|
||||||
import Select from './base/Select'
|
import Select from './base/Select'
|
||||||
import Switch from './base/Switch'
|
import Switch from './base/Switch'
|
||||||
import TextInput from './base/TextInput'
|
import TextInput from './base/TextInput'
|
||||||
|
import { CashIn, CashOut } from './cashbox/Cashbox'
|
||||||
|
|
||||||
export { Autocomplete, TextInput, Checkbox, Switch, Select, RadioGroup }
|
export {
|
||||||
|
Autocomplete,
|
||||||
|
TextInput,
|
||||||
|
Checkbox,
|
||||||
|
Switch,
|
||||||
|
Select,
|
||||||
|
RadioGroup,
|
||||||
|
CashIn,
|
||||||
|
CashOut
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import styles from './TitleSection.styles'
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
const TitleSection = ({ title, error }) => {
|
const TitleSection = ({ title, error, labels }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
return (
|
return (
|
||||||
<div className={classes.titleWrapper}>
|
<div className={classes.titleWrapper}>
|
||||||
|
|
@ -18,6 +18,7 @@ const TitleSection = ({ title, error }) => {
|
||||||
<ErrorMessage className={classes.error}>Failed to save</ErrorMessage>
|
<ErrorMessage className={classes.error}>Failed to save</ErrorMessage>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div className={classes.headerLabels}>{labels}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { mainStyles } from 'src/pages/Transactions/Transactions.styles'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
titleWrapper: {
|
titleWrapper: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|
@ -10,5 +12,6 @@ export default {
|
||||||
},
|
},
|
||||||
error: {
|
error: {
|
||||||
marginLeft: 12
|
marginLeft: 12
|
||||||
}
|
},
|
||||||
|
headerLabels: mainStyles.headerLabels
|
||||||
}
|
}
|
||||||
|
|
|
||||||
210
new-lamassu-admin/src/pages/maintenance/Cashboxes.js
Normal file
210
new-lamassu-admin/src/pages/maintenance/Cashboxes.js
Normal file
|
|
@ -0,0 +1,210 @@
|
||||||
|
import { useQuery, useMutation } from '@apollo/react-hooks'
|
||||||
|
import { gql } from 'apollo-boost'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
|
import { Table as EditableTable } from 'src/components/editableTable'
|
||||||
|
import {
|
||||||
|
CashIn,
|
||||||
|
CashOut,
|
||||||
|
CashOutFormik,
|
||||||
|
CashInFormik
|
||||||
|
} from 'src/components/inputs/cashbox/Cashbox'
|
||||||
|
import TitleSection from 'src/components/layout/TitleSection'
|
||||||
|
import { ReactComponent as ErrorIcon } from 'src/styling/icons/status/tomato.svg'
|
||||||
|
|
||||||
|
const ValidationSchema = Yup.object().shape({
|
||||||
|
name: Yup.string().required('Required'),
|
||||||
|
cashin: Yup.object()
|
||||||
|
.required('Required')
|
||||||
|
.shape({
|
||||||
|
notes: Yup.number()
|
||||||
|
.required('Required')
|
||||||
|
.integer()
|
||||||
|
.min(0)
|
||||||
|
}),
|
||||||
|
cashout1: Yup.object()
|
||||||
|
.required('Required')
|
||||||
|
.shape({
|
||||||
|
notes: Yup.number()
|
||||||
|
.required('Required')
|
||||||
|
.integer()
|
||||||
|
.min(0),
|
||||||
|
denomination: Yup.number()
|
||||||
|
.required('Required')
|
||||||
|
.integer()
|
||||||
|
.default(0)
|
||||||
|
}),
|
||||||
|
cashout2: Yup.object()
|
||||||
|
.required('Required')
|
||||||
|
.shape({
|
||||||
|
notes: Yup.number()
|
||||||
|
.required('Required')
|
||||||
|
.integer()
|
||||||
|
.min(0),
|
||||||
|
denomination: Yup.number()
|
||||||
|
.required('Required')
|
||||||
|
.integer()
|
||||||
|
.default(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const GET_MACHINES_AND_CONFIG = gql`
|
||||||
|
{
|
||||||
|
machines {
|
||||||
|
name
|
||||||
|
deviceId
|
||||||
|
cashbox
|
||||||
|
cassette1
|
||||||
|
cassette2
|
||||||
|
}
|
||||||
|
config
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const EMPTY_CASHIN_BILLS = gql`
|
||||||
|
mutation MachineAction($deviceId: ID!, $action: MachineAction!) {
|
||||||
|
machineAction(deviceId: $deviceId, action: $action) {
|
||||||
|
deviceId
|
||||||
|
cashbox
|
||||||
|
cassette1
|
||||||
|
cassette2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const RESET_CASHOUT_BILLS = gql`
|
||||||
|
mutation MachineAction(
|
||||||
|
$deviceId: ID!
|
||||||
|
$action: MachineAction!
|
||||||
|
$cassettes: [Int]!
|
||||||
|
) {
|
||||||
|
machineAction(deviceId: $deviceId, action: $action, cassettes: $cassettes) {
|
||||||
|
deviceId
|
||||||
|
cashbox
|
||||||
|
cassette1
|
||||||
|
cassette2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const Cashboxes = () => {
|
||||||
|
const [machines, setMachines] = useState([])
|
||||||
|
|
||||||
|
useQuery(GET_MACHINES_AND_CONFIG, {
|
||||||
|
onCompleted: ({ machines, config }) =>
|
||||||
|
setMachines(
|
||||||
|
machines.map(m => ({
|
||||||
|
...m,
|
||||||
|
currency: { code: config.locale_fiatCurrency ?? '' },
|
||||||
|
denominations: {
|
||||||
|
top: config[`denominations_${m.deviceId}_top`],
|
||||||
|
bottom: config[`denominations_${m.deviceId}_bottom`]
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const [resetCashOut] = useMutation(RESET_CASHOUT_BILLS, {
|
||||||
|
onError: ({ graphQLErrors, message }) => {
|
||||||
|
const errorMessage = graphQLErrors[0] ? graphQLErrors[0].message : message
|
||||||
|
// TODO: this should not be final
|
||||||
|
alert(JSON.stringify(errorMessage))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const [onEmpty] = useMutation(EMPTY_CASHIN_BILLS, {
|
||||||
|
onError: ({ graphQLErrors, message }) => {
|
||||||
|
const errorMessage = graphQLErrors[0] ? graphQLErrors[0].message : message
|
||||||
|
// TODO: this should not be final
|
||||||
|
alert(JSON.stringify(errorMessage))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const onSave = (_, { cashin, cashout1, cashout2 }) =>
|
||||||
|
resetCashOut({
|
||||||
|
variables: {
|
||||||
|
deviceId: cashin.deviceId,
|
||||||
|
action: 'resetCashOutBills',
|
||||||
|
cassettes: [Number(cashout1.notes), Number(cashout2.notes)]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const elements = [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
header: 'Machine',
|
||||||
|
width: 254,
|
||||||
|
textAlign: 'left',
|
||||||
|
view: name => <>{name}</>,
|
||||||
|
input: ({ field: { value: name } }) => <>{name}</>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cashin',
|
||||||
|
header: 'Cash-in',
|
||||||
|
width: 265,
|
||||||
|
textAlign: 'left',
|
||||||
|
view: props => <CashIn {...props} />,
|
||||||
|
input: props => <CashInFormik onEmpty={onEmpty} {...props} />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cashout1',
|
||||||
|
header: 'Cash-out 1',
|
||||||
|
width: 265,
|
||||||
|
textAlign: 'left',
|
||||||
|
view: props => <CashOut {...props} />,
|
||||||
|
input: CashOutFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cashout2',
|
||||||
|
header: 'Cash-out 2',
|
||||||
|
width: 265,
|
||||||
|
textAlign: 'left',
|
||||||
|
view: props => <CashOut {...props} />,
|
||||||
|
input: CashOutFormik
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const data = machines.map(
|
||||||
|
({
|
||||||
|
name,
|
||||||
|
cassette1,
|
||||||
|
cassette2,
|
||||||
|
currency,
|
||||||
|
denominations: { top, bottom },
|
||||||
|
cashbox,
|
||||||
|
deviceId
|
||||||
|
}) => ({
|
||||||
|
id: deviceId,
|
||||||
|
name,
|
||||||
|
cashin: { notes: cashbox, deviceId },
|
||||||
|
cashout1: { notes: cassette1, denomination: top, currency },
|
||||||
|
cashout2: { notes: cassette2, denomination: bottom, currency }
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TitleSection
|
||||||
|
title="Cashboxes"
|
||||||
|
labels={
|
||||||
|
<>
|
||||||
|
<ErrorIcon />
|
||||||
|
<span>Action required</span>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<EditableTable
|
||||||
|
name="cashboxes"
|
||||||
|
enableEdit
|
||||||
|
elements={elements}
|
||||||
|
data={data}
|
||||||
|
save={onSave}
|
||||||
|
validationSchema={ValidationSchema}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Cashboxes
|
||||||
|
|
@ -18,6 +18,8 @@ import WalletSettings from 'src/pages/Wallet/Wallet'
|
||||||
import MachineStatus from 'src/pages/maintenance/MachineStatus'
|
import MachineStatus from 'src/pages/maintenance/MachineStatus'
|
||||||
import { namespaces } from 'src/utils/config'
|
import { namespaces } from 'src/utils/config'
|
||||||
|
|
||||||
|
import Cashboxes from '../pages/maintenance/Cashboxes'
|
||||||
|
|
||||||
const tree = [
|
const tree = [
|
||||||
{
|
{
|
||||||
key: 'transactions',
|
key: 'transactions',
|
||||||
|
|
@ -56,6 +58,12 @@ const tree = [
|
||||||
label: 'Machine Status',
|
label: 'Machine Status',
|
||||||
route: '/maintenance/machine-status',
|
route: '/maintenance/machine-status',
|
||||||
component: MachineStatus
|
component: MachineStatus
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'cashboxes',
|
||||||
|
label: 'Cashboxes',
|
||||||
|
route: '/maintenance/cashboxes',
|
||||||
|
component: Cashboxes
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,13 @@ import extendJss from 'jss-plugin-extend'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { ActionButton, Button, Link } from 'src/components/buttons'
|
import { ActionButton, Button, Link } from 'src/components/buttons'
|
||||||
import { TextInput, Switch } from 'src/components/inputs'
|
import {
|
||||||
|
Radio,
|
||||||
|
TextInput,
|
||||||
|
Switch,
|
||||||
|
CashIn,
|
||||||
|
CashOut
|
||||||
|
} from 'src/components/inputs'
|
||||||
import { ReactComponent as AuthorizeIconReversed } from 'src/styling/icons/button/authorize/white.svg'
|
import { ReactComponent as AuthorizeIconReversed } from 'src/styling/icons/button/authorize/white.svg'
|
||||||
import { ReactComponent as AuthorizeIcon } from 'src/styling/icons/button/authorize/zodiac.svg'
|
import { ReactComponent as AuthorizeIcon } from 'src/styling/icons/button/authorize/zodiac.svg'
|
||||||
|
|
||||||
|
|
@ -178,6 +184,35 @@ story.add('ConfirmDialog', () => (
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
))
|
))
|
||||||
|
|
||||||
|
story.add('Cashbox', () => (
|
||||||
|
<Wrapper>
|
||||||
|
<div>
|
||||||
|
<CashIn percent={0} notes={0} />
|
||||||
|
<hr />
|
||||||
|
<CashIn percent={49} notes={19} />
|
||||||
|
<hr />
|
||||||
|
<CashIn percent={50} notes={20} />
|
||||||
|
<hr />
|
||||||
|
<CashIn percent={51} notes={22} />
|
||||||
|
<hr />
|
||||||
|
<CashIn percent={99} notes={39} />
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<CashOut percent={0} notes={0} denomination={20} />
|
||||||
|
<hr />
|
||||||
|
<CashOut percent={49} notes={19} denomination={20} />
|
||||||
|
<hr />
|
||||||
|
<CashOut percent={50} notes={20} denomination={20} />
|
||||||
|
<hr />
|
||||||
|
<CashOut percent={51.00001} notes={22} denomination={20} />
|
||||||
|
</div>
|
||||||
|
</Wrapper>
|
||||||
|
))
|
||||||
|
|
||||||
|
story.add('Radio', () => <Radio label="Hehe" />)
|
||||||
|
|
||||||
const typographyStory = storiesOf('Typography', module)
|
const typographyStory = storiesOf('Typography', module)
|
||||||
typographyStory.add('H1', () => <H1>Hehehe</H1>)
|
typographyStory.add('H1', () => <H1>Hehehe</H1>)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue