fix: cancel cashout txs
This commit is contained in:
parent
e5ab87c2a5
commit
e952682917
4 changed files with 70 additions and 29 deletions
|
|
@ -1,25 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const uuid = require('@fczbkk/uuid4')
|
|
||||||
|
|
||||||
const tx = require('../lib/cash-out/cash-out-tx.js')
|
|
||||||
|
|
||||||
const argv = process.argv.slice(2)
|
|
||||||
|
|
||||||
if (argv.length !== 1) {
|
|
||||||
console.log('Usage: lamassu-cancel <tx-id>')
|
|
||||||
console.log('Cancels the cash out transaction with given tx-id so it cannot be dispensed.')
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
const txId = argv[0]
|
|
||||||
|
|
||||||
if (!uuid.validate(txId)) {
|
|
||||||
console.log('tx-id must be valid uuid. e.g.: f8093ded-c542-4916-8ab5-6ebeceb287c1')
|
|
||||||
process.exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.cancel(txId)
|
|
||||||
.then(() => console.log('Success.'))
|
|
||||||
.catch(err => console.log(`Error: ${err.message}`))
|
|
||||||
.then(() => process.exit(0))
|
|
||||||
|
|
@ -19,6 +19,7 @@ const bills = require('../bills')
|
||||||
const anonymous = require('../../constants').anonymousCustomer
|
const anonymous = require('../../constants').anonymousCustomer
|
||||||
|
|
||||||
const serverVersion = require('../../../package.json').version
|
const serverVersion = require('../../../package.json').version
|
||||||
|
const cashOutTx = require('../../cash-out/cash-out-tx')
|
||||||
const transactions = require('../transactions')
|
const transactions = require('../transactions')
|
||||||
const funding = require('../funding')
|
const funding = require('../funding')
|
||||||
const forex = require('../../forex')
|
const forex = require('../../forex')
|
||||||
|
|
@ -344,6 +345,7 @@ const typeDefs = gql`
|
||||||
deletePromoCode(codeId: ID!): PromoCode
|
deletePromoCode(codeId: ID!): PromoCode
|
||||||
toggleClearNotification(id: ID!, read: Boolean!): Notification
|
toggleClearNotification(id: ID!, read: Boolean!): Notification
|
||||||
clearAllNotifications: Notification
|
clearAllNotifications: Notification
|
||||||
|
cancelCashOutTransaction(id: ID): Transaction
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -440,7 +442,8 @@ const resolvers = {
|
||||||
createPromoCode: (...[, { code, discount }]) => promoCodeManager.createPromoCode(code, discount),
|
createPromoCode: (...[, { code, discount }]) => promoCodeManager.createPromoCode(code, discount),
|
||||||
deletePromoCode: (...[, { codeId }]) => promoCodeManager.deletePromoCode(codeId),
|
deletePromoCode: (...[, { codeId }]) => promoCodeManager.deletePromoCode(codeId),
|
||||||
toggleClearNotification: (...[, { id, read }]) => notifierQueries.setRead(id, read),
|
toggleClearNotification: (...[, { id, read }]) => notifierQueries.setRead(id, read),
|
||||||
clearAllNotifications: () => notifierQueries.markAllAsRead()
|
clearAllNotifications: () => notifierQueries.markAllAsRead(),
|
||||||
|
cancelCashOutTransaction: (...[, { id }]) => cashOutTx.cancel(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
|
import { useMutation } from '@apollo/react-hooks'
|
||||||
import { makeStyles, Box } from '@material-ui/core'
|
import { makeStyles, Box } from '@material-ui/core'
|
||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
|
import gql from 'graphql-tag'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import React, { memo } from 'react'
|
import React, { memo, useState } from 'react'
|
||||||
|
|
||||||
|
import { ConfirmDialog } from 'src/components/ConfirmDialog'
|
||||||
import { HoverableTooltip } from 'src/components/Tooltip'
|
import { HoverableTooltip } from 'src/components/Tooltip'
|
||||||
import { IDButton } from 'src/components/buttons'
|
import { IDButton, ActionButton } from 'src/components/buttons'
|
||||||
import { P, Label1 } from 'src/components/typography'
|
import { P, Label1 } from 'src/components/typography'
|
||||||
import { ReactComponent as CardIdInverseIcon } from 'src/styling/icons/ID/card/white.svg'
|
import { ReactComponent as CardIdInverseIcon } from 'src/styling/icons/ID/card/white.svg'
|
||||||
import { ReactComponent as CardIdIcon } from 'src/styling/icons/ID/card/zodiac.svg'
|
import { ReactComponent as CardIdIcon } from 'src/styling/icons/ID/card/zodiac.svg'
|
||||||
|
|
@ -12,6 +15,8 @@ import { ReactComponent as PhoneIdInverseIcon } from 'src/styling/icons/ID/phone
|
||||||
import { ReactComponent as PhoneIdIcon } from 'src/styling/icons/ID/phone/zodiac.svg'
|
import { ReactComponent as PhoneIdIcon } from 'src/styling/icons/ID/phone/zodiac.svg'
|
||||||
import { ReactComponent as CamIdInverseIcon } from 'src/styling/icons/ID/photo/white.svg'
|
import { ReactComponent as CamIdInverseIcon } from 'src/styling/icons/ID/photo/white.svg'
|
||||||
import { ReactComponent as CamIdIcon } from 'src/styling/icons/ID/photo/zodiac.svg'
|
import { ReactComponent as CamIdIcon } from 'src/styling/icons/ID/photo/zodiac.svg'
|
||||||
|
import { ReactComponent as CancelInverseIcon } from 'src/styling/icons/button/cancel/white.svg'
|
||||||
|
import { ReactComponent as CancelIcon } from 'src/styling/icons/button/cancel/zodiac.svg'
|
||||||
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'
|
||||||
import { URI } from 'src/utils/apollo'
|
import { URI } from 'src/utils/apollo'
|
||||||
|
|
@ -24,6 +29,14 @@ import { getStatus, getStatusDetails } from './helper'
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
const CANCEL_TRANSACTION = gql`
|
||||||
|
mutation cancelCashOutTransaction($id: ID!) {
|
||||||
|
cancelCashOutTransaction(id: $id) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
const formatAddress = (cryptoCode = '', address = '') =>
|
const formatAddress = (cryptoCode = '', address = '') =>
|
||||||
formatCryptoAddress(cryptoCode, address).replace(/(.{5})/g, '$1 ')
|
formatCryptoAddress(cryptoCode, address).replace(/(.{5})/g, '$1 ')
|
||||||
|
|
||||||
|
|
@ -34,6 +47,13 @@ const Label = ({ children }) => {
|
||||||
|
|
||||||
const DetailsRow = ({ it: tx }) => {
|
const DetailsRow = ({ it: tx }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
const [action, setAction] = useState({ command: null })
|
||||||
|
const [errorMessage, setErrorMessage] = useState('')
|
||||||
|
|
||||||
|
const [cancelCashOutTransaction] = useMutation(CANCEL_TRANSACTION, {
|
||||||
|
onError: ({ message }) => setErrorMessage(message ?? 'An error occurred.'),
|
||||||
|
refetchQueries: () => ['transactions']
|
||||||
|
})
|
||||||
|
|
||||||
const fiat = Number.parseFloat(tx.fiat)
|
const fiat = Number.parseFloat(tx.fiat)
|
||||||
const crypto = toUnit(new BigNumber(tx.cryptoAtoms), tx.cryptoCode)
|
const crypto = toUnit(new BigNumber(tx.cryptoAtoms), tx.cryptoCode)
|
||||||
|
|
@ -197,7 +217,7 @@ const DetailsRow = ({ it: tx }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.lastRow}>
|
<div className={classes.lastRow}>
|
||||||
<div>
|
<div className={classes.status}>
|
||||||
{getStatusDetails(tx) ? (
|
{getStatusDetails(tx) ? (
|
||||||
<HoverableTooltip parentElements={errorElements} width={200}>
|
<HoverableTooltip parentElements={errorElements} width={200}>
|
||||||
<P>{getStatusDetails(tx)}</P>
|
<P>{getStatusDetails(tx)}</P>
|
||||||
|
|
@ -205,8 +225,42 @@ const DetailsRow = ({ it: tx }) => {
|
||||||
) : (
|
) : (
|
||||||
errorElements
|
errorElements
|
||||||
)}
|
)}
|
||||||
|
{tx.txClass === 'cashOut' && getStatus(tx) !== 'Cancelled' && (
|
||||||
|
<ActionButton
|
||||||
|
color="primary"
|
||||||
|
Icon={CancelIcon}
|
||||||
|
InverseIcon={CancelInverseIcon}
|
||||||
|
className={classes.cancelTransaction}
|
||||||
|
onClick={() =>
|
||||||
|
setAction({
|
||||||
|
command: 'cancelTx'
|
||||||
|
})
|
||||||
|
}>
|
||||||
|
Cancel transaction
|
||||||
|
</ActionButton>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ConfirmDialog
|
||||||
|
open={action.command === 'cancelTx'}
|
||||||
|
title={`Cancel this transaction?`}
|
||||||
|
errorMessage={errorMessage}
|
||||||
|
toBeConfirmed={tx.machineName}
|
||||||
|
message={`The user will not be able to redeem the cash, even if they subsequently send the required coins. If they've already sent you coins, you'll need to reconcile this transaction with them manually.`}
|
||||||
|
onConfirmed={() => {
|
||||||
|
setErrorMessage(null)
|
||||||
|
setAction({ command: null })
|
||||||
|
cancelCashOutTransaction({
|
||||||
|
variables: {
|
||||||
|
id: tx.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
onDissmised={() => {
|
||||||
|
setAction({ command: null })
|
||||||
|
setErrorMessage(null)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,15 @@ export default {
|
||||||
address: {
|
address: {
|
||||||
width: 280
|
width: 280
|
||||||
},
|
},
|
||||||
|
cancelTransaction: {
|
||||||
|
width: 160
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
width: 230,
|
||||||
|
'& > button': {
|
||||||
|
marginTop: 20
|
||||||
|
}
|
||||||
|
},
|
||||||
transactionId: {
|
transactionId: {
|
||||||
width: 280
|
width: 280
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue