Merge pull request #398 from liordino/feature/create-receipt-printing-page

feat: create receipt printing page
This commit is contained in:
Rafael Taranto 2020-05-09 19:58:14 +01:00 committed by GitHub
commit d65482958a
9 changed files with 353 additions and 23 deletions

View file

@ -1,4 +1,5 @@
import { makeStyles } from '@material-ui/core/styles' import { makeStyles } from '@material-ui/core/styles'
import classnames from 'classnames'
import React, { useState, memo } from 'react' import React, { useState, memo } from 'react'
import { Link } from 'src/components/buttons' import { Link } from 'src/components/buttons'
@ -30,6 +31,7 @@ const BooleanPropertiesTable = memo(
} }
const innerCancel = () => { const innerCancel = () => {
setRadioGroupValues(elements)
setEditing(false) setEditing(false)
} }
@ -79,8 +81,9 @@ const BooleanPropertiesTable = memo(
{radioGroupValues && {radioGroupValues &&
radioGroupValues.map((element, idx) => ( radioGroupValues.map((element, idx) => (
<TableRow key={idx} size="sm" className={classes.tableRow}> <TableRow key={idx} size="sm" className={classes.tableRow}>
<TableCell className={classes.tableCell}> <TableCell className={classes.leftTableCell}>
{element.display} {element.display}
</TableCell>
{editing && ( {editing && (
<RadioGroup <RadioGroup
options={radioButtonOptions} options={radioButtonOptions}
@ -91,11 +94,18 @@ const BooleanPropertiesTable = memo(
event.target.value === 'true' event.target.value === 'true'
) )
} }
className={classes.radioButtons} className={classnames(
classes.radioButtons,
classes.rightTableCell
)}
/>
)}
{!editing && (
<BooleanCell
className={classes.rightTableCell}
value={element.value}
/> />
)} )}
{!editing && <BooleanCell value={element.value} />}
</TableCell>
</TableRow> </TableRow>
))} ))}
</TableBody> </TableBody>

View file

@ -1,5 +1,5 @@
import baseStyles from 'src/pages/Logs.styles' import baseStyles from 'src/pages/Logs.styles'
import { tableCellColor, zircon } from 'src/styling/variables' import { backgroundColor, zircon } from 'src/styling/variables'
const { fillColumn } = baseStyles const { fillColumn } = baseStyles
@ -14,20 +14,28 @@ const booleanPropertiesTableStyles = {
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
'&:nth-child(even)': { '&:nth-child(even)': {
backgroundColor: tableCellColor backgroundColor: backgroundColor
}, },
'&:nth-child(odd)': { '&:nth-child(odd)': {
backgroundColor: zircon backgroundColor: zircon
}, },
minHeight: 32,
height: 'auto',
padding: [[8, 16, 8, 24]],
boxShadow: '0 0 0 0 rgba(0, 0, 0, 0)' boxShadow: '0 0 0 0 rgba(0, 0, 0, 0)'
}, },
tableCell: { leftTableCell: {
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'left',
width: '100%', width: 200,
height: 32, padding: [0]
padding: [[5, 14, 5, 20]] },
rightTableCell: {
display: 'flex',
alignItems: 'center',
justifyContent: 'right',
padding: [0]
}, },
transparentButton: { transparentButton: {
'& > *': { '& > *': {
@ -51,7 +59,7 @@ const booleanPropertiesTableStyles = {
radioButtons: { radioButtons: {
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
marginRight: -15 margin: [-15]
}, },
rightLink: { rightLink: {
marginLeft: '20px' marginLeft: '20px'

View file

@ -0,0 +1,74 @@
import { makeStyles } from '@material-ui/core/styles'
import React, { useState, memo } from 'react'
import { Link } from 'src/components/buttons'
import { RadioGroup } from 'src/components/inputs'
import { H4, P } from 'src/components/typography'
import { ReactComponent as EditIconDisabled } from 'src/styling/icons/action/edit/disabled.svg'
import { ReactComponent as EditIcon } from 'src/styling/icons/action/edit/enabled.svg'
import { editablePropertyStyles } from './EditableProperty.styles'
const useStyles = makeStyles(editablePropertyStyles)
const EditableProperty = memo(
({ title, prefixText, disabled, options, code, save }) => {
const [editing, setEditing] = useState(false)
const [currentCode, setCurrentCode] = useState(code)
const classes = useStyles()
const innerSave = () => {
save(currentCode)
setEditing(false)
}
const innerCancel = () => setEditing(false)
return (
<>
<div className={classes.rowWrapper}>
<H4>{title}</H4>
{editing ? (
<div className={classes.leftSpace}>
<Link
className={classes.leftSpace}
onClick={innerCancel}
color="secondary">
Cancel
</Link>
<Link
className={classes.leftSpace}
onClick={innerSave}
color="primary">
Save
</Link>
</div>
) : (
<div className={classes.transparentButton}>
<button disabled={disabled} onClick={() => setEditing(true)}>
{disabled ? <EditIconDisabled /> : <EditIcon />}
</button>
</div>
)}
</div>
{editing ? (
<RadioGroup
options={options}
value={currentCode}
onChange={event => setCurrentCode(event.target.value)}
className={classes.radioButtons}
/>
) : (
<P>
{`${prefixText} ${options
.find(it => it.code === currentCode)
.display.toLowerCase()}`}
</P>
)}
</>
)
}
)
export default EditableProperty

View file

@ -0,0 +1,32 @@
const editablePropertyStyles = {
transparentButton: {
'& > *': {
margin: 'auto 12px'
},
'& button': {
border: 'none',
backgroundColor: 'transparent',
cursor: 'pointer'
}
},
rowWrapper: {
display: 'flex',
alignItems: 'center',
position: 'relative',
flex: 'wrap'
},
rightAligned: {
display: 'flex',
position: 'absolute',
right: 0
},
radioButtons: {
display: 'flex',
flexDirection: 'row'
},
leftSpace: {
marginLeft: '20px'
}
}
export { editablePropertyStyles }

View file

@ -0,0 +1,3 @@
import EditableProperty from './EditableProperty'
export { EditableProperty }

View file

@ -9,6 +9,7 @@ import logsStyles from '../Logs.styles'
import CoinAtmRadar from './CoinATMRadar' import CoinAtmRadar from './CoinATMRadar'
import ContactInfo from './ContactInfo' import ContactInfo from './ContactInfo'
import ReceiptPrinting from './ReceiptPrinting'
import TermsConditions from './TermsConditions' import TermsConditions from './TermsConditions'
const localStyles = { const localStyles = {
@ -52,6 +53,7 @@ const OperatorInfo = () => {
/> />
<div className={classes.contentWrapper}> <div className={classes.contentWrapper}>
{isSelected(CONTACT_INFORMATION) && <ContactInfo />} {isSelected(CONTACT_INFORMATION) && <ContactInfo />}
{isSelected(RECEIPT) && <ReceiptPrinting />}
{isSelected(TERMS_CONDITIONS) && <TermsConditions />} {isSelected(TERMS_CONDITIONS) && <TermsConditions />}
{isSelected(COIN_ATM_RADAR) && <CoinAtmRadar />} {isSelected(COIN_ATM_RADAR) && <CoinAtmRadar />}
</div> </div>

View file

@ -0,0 +1,187 @@
// import { makeStyles } from '@material-ui/core/styles'
import { useQuery, useMutation } from '@apollo/react-hooks'
import { gql } from 'apollo-boost'
import React, { useState, memo } from 'react'
import { BooleanPropertiesTable } from 'src/components/booleanPropertiesTable'
import { EditableProperty } from 'src/components/editableProperty'
// import { ActionButton } from 'src/components/buttons'
// import { ReactComponent as UploadIcon } from 'src/styling/icons/button/upload/zodiac.svg'
// import { ReactComponent as UploadIconInverse } from 'src/styling/icons/button/upload/white.svg'
// import { TextInput } from 'src/components/inputs'
// import { mainStyles } from './ReceiptPrinting.styles'
// const useStyles = makeStyles(mainStyles)
const initialValues = {
active: 'off',
// logo: false,
operatorWebsite: false,
operatorEmail: false,
operatorPhone: false,
companyRegistration: false,
machineLocation: false,
customerNameOrPhoneNumber: false,
// commission: false,
exchangeRate: false,
addressQRCode: false
// customText: false,
// customTextContent: ''
}
const GET_CONFIG = gql`
{
config
}
`
const SAVE_CONFIG = gql`
mutation Save($config: JSONObject) {
saveConfig(config: $config)
}
`
const receiptPrintingOptions = [
{
code: 'off',
display: 'Off'
},
{
code: 'optional',
display: 'Optional (ask user)'
},
{
code: 'on',
display: 'On'
}
]
const ReceiptPrinting = memo(() => {
const [receiptPrintingConfig, setReceiptPrintingConfig] = useState(null)
// const classes = useStyles()
// TODO: treat errors on useMutation and useQuery
const [saveConfig] = useMutation(SAVE_CONFIG, {
onCompleted: configResponse =>
setReceiptPrintingConfig(configResponse.saveConfig.receiptPrinting)
})
useQuery(GET_CONFIG, {
onCompleted: configResponse => {
setReceiptPrintingConfig(
configResponse?.config?.receiptPrinting ?? initialValues
)
}
})
const save = it =>
saveConfig({ variables: { config: { receiptPrinting: it } } })
if (!receiptPrintingConfig) return null
return (
<>
<EditableProperty
title={'Receipt options'}
prefixText={'Receipt printing'}
disabled={false}
options={receiptPrintingOptions}
code={receiptPrintingConfig.active}
save={it =>
saveConfig({
variables: { config: { receiptPrinting: { active: it } } }
})
}
/>
<BooleanPropertiesTable
title={'Visible on the receipt (optionals)'}
disabled={receiptPrintingConfig.active === 'off'}
data={receiptPrintingConfig}
elements={[
// {
// name: 'logo',
// display: (
// <>
// {'Logo'}
// <ActionButton
// className={classes.actionButton}
// Icon={UploadIcon}
// InverseIcon={UploadIconInverse}
// color={'primary'}
// onClick={() => {
// // TODO: make the replace logo feature
// }}>
// Replace logo
// </ActionButton>
// </>
// ),
// value: receiptPrintingConfig.logo
// },
{
name: 'operatorWebsite',
display: 'Operator website',
value: receiptPrintingConfig.operatorWebsite
},
{
name: 'operatorEmail',
display: 'Operator email',
value: receiptPrintingConfig.operatorEmail
},
{
name: 'operatorPhone',
display: 'Operator phone',
value: receiptPrintingConfig.operatorPhone
},
{
name: 'companyRegistration',
display: 'Company registration',
value: receiptPrintingConfig.companyRegistration
},
{
name: 'machineLocation',
display: 'Machine location',
value: receiptPrintingConfig.machineLocation
},
{
name: 'customerNameOrPhoneNumber',
display: 'Customer name or phone number (if known)',
value: receiptPrintingConfig.customerNameOrPhoneNumber
},
// {
// name: 'commission',
// display: 'Commission',
// value: receiptPrintingConfig.commission
// },
{
name: 'exchangeRate',
display: 'Exchange rate',
value: receiptPrintingConfig.exchangeRate
},
{
name: 'addressQRCode',
display: 'Address QR code',
value: receiptPrintingConfig.addressQRCode
}
// {
// name: 'customText',
// display: 'Custom text',
// value: receiptPrintingConfig.customText
// }
]}
save={save}
/>
{/* TODO: textInput should appear only when table is in edit mode, and have it's value saved along with the table values */}
{/* <TextInput
className={classes.textInput}
label={'Custom text content'}
multiline
rows="4"
defaultValue={receiptPrintingConfig.customTextContent}
/> */}
{/* TODO: add receipt preview on the right side of the page */}
</>
)
})
export default ReceiptPrinting

View file

@ -0,0 +1,11 @@
const mainStyles = {
textInput: {
margin: [[28, 20]],
width: 304
},
actionButton: {
margin: [[0, 24]]
}
}
export { mainStyles }

View file

@ -0,0 +1,3 @@
import ReceiptPrinting from './ReceiptPrinting'
export default ReceiptPrinting