Chore: fix regressions caused by rebase
This commit is contained in:
parent
ef60b15d82
commit
0d6349dbf4
26 changed files with 10471 additions and 34310 deletions
|
|
@ -9,8 +9,6 @@ const helper = require('./cash-out-helper')
|
||||||
const cashOutActions = require('./cash-out-actions')
|
const cashOutActions = require('./cash-out-actions')
|
||||||
const cashOutLow = require('./cash-out-low')
|
const cashOutLow = require('./cash-out-low')
|
||||||
|
|
||||||
const notifier = require("../notifier/index")
|
|
||||||
|
|
||||||
const toObj = helper.toObj
|
const toObj = helper.toObj
|
||||||
|
|
||||||
module.exports = {atomic}
|
module.exports = {atomic}
|
||||||
|
|
@ -124,9 +122,8 @@ function updateCassettes (t, tx) {
|
||||||
tx.deviceId
|
tx.deviceId
|
||||||
]
|
]
|
||||||
|
|
||||||
return t.one(sql, values).then(r => {
|
return t.one(sql, values)
|
||||||
return socket.emit(_.assign(r, {op: 'cassetteUpdate', deviceId: tx.deviceId}))
|
.then(r => socket.emit(_.assign(r, {op: 'cassetteUpdate', deviceId: tx.deviceId})))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function wasJustAuthorized (oldTx, newTx, isZeroConf) {
|
function wasJustAuthorized (oldTx, newTx, isZeroConf) {
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,12 @@ function printSmsAlerts (alertRec, config) {
|
||||||
const code = entry[0]
|
const code = entry[0]
|
||||||
const machineNames = _.filter(
|
const machineNames = _.filter(
|
||||||
_.negate(_.isEmpty),
|
_.negate(_.isEmpty),
|
||||||
_.map('machineName', entry[1]),
|
_.map('machineName', entry[1])
|
||||||
)
|
)
|
||||||
|
|
||||||
const cryptoCodes = _.filter(
|
const cryptoCodes = _.filter(
|
||||||
_.negate(_.isEmpty),
|
_.negate(_.isEmpty),
|
||||||
_.map('cryptoCode', entry[1]),
|
_.map('cryptoCode', entry[1])
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -196,5 +196,5 @@ module.exports = {
|
||||||
formatCurrency,
|
formatCurrency,
|
||||||
formatAge,
|
formatAge,
|
||||||
buildDetail,
|
buildDetail,
|
||||||
deviceAlerts,
|
deviceAlerts
|
||||||
}
|
}
|
||||||
|
|
|
||||||
217
lib/plugins.js
217
lib/plugins.js
|
|
@ -55,8 +55,7 @@ function plugins (settings, deviceId) {
|
||||||
? undefined
|
? undefined
|
||||||
: BN(1).add(BN(commissions.cashOut).div(100))
|
: BN(1).add(BN(commissions.cashOut).div(100))
|
||||||
|
|
||||||
if (Date.now() - rateRec.timestamp > STALE_TICKER)
|
if (Date.now() - rateRec.timestamp > STALE_TICKER) return logger.warn('Stale rate for ' + cryptoCode)
|
||||||
return logger.warn('Stale rate for ' + cryptoCode)
|
|
||||||
const rate = rateRec.rates
|
const rate = rateRec.rates
|
||||||
|
|
||||||
withCommission ? rates[cryptoCode] = {
|
withCommission ? rates[cryptoCode] = {
|
||||||
|
|
@ -90,10 +89,8 @@ function plugins (settings, deviceId) {
|
||||||
|
|
||||||
cryptoCodes.forEach((cryptoCode, i) => {
|
cryptoCodes.forEach((cryptoCode, i) => {
|
||||||
const balanceRec = balanceRecs[i]
|
const balanceRec = balanceRecs[i]
|
||||||
if (!balanceRec)
|
if (!balanceRec) return logger.warn('No balance for ' + cryptoCode + ' yet')
|
||||||
return logger.warn('No balance for ' + cryptoCode + ' yet')
|
if (Date.now() - balanceRec.timestamp > STALE_BALANCE) return logger.warn('Stale balance for ' + cryptoCode)
|
||||||
if (Date.now() - balanceRec.timestamp > STALE_BALANCE)
|
|
||||||
return logger.warn('Stale balance for ' + cryptoCode)
|
|
||||||
|
|
||||||
balances[cryptoCode] = balanceRec.balance
|
balances[cryptoCode] = balanceRec.balance
|
||||||
})
|
})
|
||||||
|
|
@ -113,13 +110,10 @@ function plugins (settings, deviceId) {
|
||||||
const sumTxs = (sum, tx) => {
|
const sumTxs = (sum, tx) => {
|
||||||
const bills = tx.bills
|
const bills = tx.bills
|
||||||
const sameDenominations = a => a[0].denomination === a[1].denomination
|
const sameDenominations = a => a[0].denomination === a[1].denomination
|
||||||
const doDenominationsMatch = _.every(
|
const doDenominationsMatch = _.every(sameDenominations, _.zip(cassettes, bills))
|
||||||
sameDenominations,
|
|
||||||
_.zip(cassettes, bills)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!doDenominationsMatch) {
|
if (!doDenominationsMatch) {
|
||||||
throw new Error("Denominations don't add up, cassettes were changed.")
|
throw new Error('Denominations don\'t add up, cassettes were changed.')
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.map(r => r[0] + r[1].provisioned, _.zip(sum, tx.bills))
|
return _.map(r => r[0] + r[1].provisioned, _.zip(sum, tx.bills))
|
||||||
|
|
@ -195,23 +189,18 @@ function plugins (settings, deviceId) {
|
||||||
order by id desc
|
order by id desc
|
||||||
limit 1`
|
limit 1`
|
||||||
|
|
||||||
return db.one(sql, ['config']).then(row => row.id)
|
return db.one(sql, ['config'])
|
||||||
|
.then(row => row.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapCoinSettings (coinParams) {
|
function mapCoinSettings (coinParams) {
|
||||||
const cryptoCode = coinParams[0]
|
const cryptoCode = coinParams[0]
|
||||||
const cryptoNetwork = coinParams[1]
|
const cryptoNetwork = coinParams[1]
|
||||||
const commissions = configManager.getCommissions(
|
const commissions = configManager.getCommissions(cryptoCode, deviceId, settings.config)
|
||||||
cryptoCode,
|
|
||||||
deviceId,
|
|
||||||
settings.config
|
|
||||||
)
|
|
||||||
const minimumTx = BN(commissions.minimumTx)
|
const minimumTx = BN(commissions.minimumTx)
|
||||||
const cashInFee = BN(commissions.fixedFee)
|
const cashInFee = BN(commissions.fixedFee)
|
||||||
const cashInCommission = BN(commissions.cashIn)
|
const cashInCommission = BN(commissions.cashIn)
|
||||||
const cashOutCommission = _.isNumber(commissions.cashOut)
|
const cashOutCommission = _.isNumber(commissions.cashOut) ? BN(commissions.cashOut) : null
|
||||||
? BN(commissions.cashOut)
|
|
||||||
: null
|
|
||||||
const cryptoRec = coinUtils.getCryptoCurrency(cryptoCode)
|
const cryptoRec = coinUtils.getCryptoCurrency(cryptoCode)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -225,25 +214,15 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function pollQueries (
|
function pollQueries (serialNumber, deviceTime, deviceRec, machineVersion, machineModel) {
|
||||||
serialNumber,
|
|
||||||
deviceTime,
|
|
||||||
deviceRec,
|
|
||||||
machineVersion,
|
|
||||||
machineModel
|
|
||||||
) {
|
|
||||||
const localeConfig = configManager.getLocale(deviceId, settings.config)
|
const localeConfig = configManager.getLocale(deviceId, settings.config)
|
||||||
|
|
||||||
const fiatCode = localeConfig.fiatCurrency
|
const fiatCode = localeConfig.fiatCurrency
|
||||||
const cryptoCodes = localeConfig.cryptoCurrencies
|
const cryptoCodes = localeConfig.cryptoCurrencies
|
||||||
|
|
||||||
const tickerPromises = cryptoCodes.map(c =>
|
const tickerPromises = cryptoCodes.map(c => ticker.getRates(settings, fiatCode, c))
|
||||||
ticker.getRates(settings, fiatCode, c)
|
|
||||||
)
|
|
||||||
const balancePromises = cryptoCodes.map(c => fiatBalance(fiatCode, c))
|
const balancePromises = cryptoCodes.map(c => fiatBalance(fiatCode, c))
|
||||||
const testnetPromises = cryptoCodes.map(c =>
|
const testnetPromises = cryptoCodes.map(c => wallet.cryptoNetwork(settings, c))
|
||||||
wallet.cryptoNetwork(settings, c)
|
|
||||||
)
|
|
||||||
const pingPromise = recordPing(deviceTime, machineVersion, machineModel)
|
const pingPromise = recordPing(deviceTime, machineVersion, machineModel)
|
||||||
const currentConfigVersionPromise = fetchCurrentConfigVersion()
|
const currentConfigVersionPromise = fetchCurrentConfigVersion()
|
||||||
const currentAvailablePromoCodes = promoCodes.getNumberOfAvailablePromoCodes()
|
const currentAvailablePromoCodes = promoCodes.getNumberOfAvailablePromoCodes()
|
||||||
|
|
@ -278,12 +257,7 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendCoins (tx) {
|
function sendCoins (tx) {
|
||||||
return wallet.sendCoins(
|
return wallet.sendCoins(settings, tx.toAddress, tx.cryptoAtoms, tx.cryptoCode)
|
||||||
settings,
|
|
||||||
tx.toAddress,
|
|
||||||
tx.cryptoAtoms,
|
|
||||||
tx.cryptoCode
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function recordPing (deviceTime, version, model) {
|
function recordPing (deviceTime, version, model) {
|
||||||
|
|
@ -294,18 +268,11 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
db.none(
|
db.none(`insert into machine_pings(device_id, device_time) values($1, $2)
|
||||||
`insert into machine_pings(device_id, device_time) values($1, $2)
|
ON CONFLICT (device_id) DO UPDATE SET device_time = $2, updated = now()`, [deviceId, deviceTime]),
|
||||||
ON CONFLICT (device_id) DO UPDATE SET device_time = $2, updated = now()`,
|
db.none(pgp.helpers.update(devices, null, 'devices') + `WHERE device_id = ${deviceId}`, {
|
||||||
[deviceId, deviceTime]
|
|
||||||
),
|
|
||||||
db.none(
|
|
||||||
pgp.helpers.update(devices, null, 'devices') +
|
|
||||||
'WHERE device_id = ${deviceId}',
|
|
||||||
{
|
|
||||||
deviceId
|
deviceId
|
||||||
}
|
})
|
||||||
)
|
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -337,15 +304,12 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function fiatBalance (fiatCode, cryptoCode) {
|
function fiatBalance (fiatCode, cryptoCode) {
|
||||||
const commissions = configManager.getCommissions(
|
const commissions = configManager.getCommissions(cryptoCode, deviceId, settings.config)
|
||||||
cryptoCode,
|
|
||||||
deviceId,
|
|
||||||
settings.config
|
|
||||||
)
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
ticker.getRates(settings, fiatCode, cryptoCode),
|
ticker.getRates(settings, fiatCode, cryptoCode),
|
||||||
wallet.balance(settings, cryptoCode)
|
wallet.balance(settings, cryptoCode)
|
||||||
]).then(([rates, balanceRec]) => {
|
])
|
||||||
|
.then(([rates, balanceRec]) => {
|
||||||
if (!rates || !balanceRec) return null
|
if (!rates || !balanceRec) return null
|
||||||
|
|
||||||
const rawRate = rates.rates.ask
|
const rawRate = rates.rates.ask
|
||||||
|
|
@ -382,7 +346,8 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sms.sendMessage(settings, rec).then(() => {
|
return sms.sendMessage(settings, rec)
|
||||||
|
.then(() => {
|
||||||
const sql = 'update cash_out_txs set notified=$1 where id=$2'
|
const sql = 'update cash_out_txs set notified=$1 where id=$2'
|
||||||
const values = [true, tx.id]
|
const values = [true, tx.id]
|
||||||
|
|
||||||
|
|
@ -396,17 +361,14 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearOldLogs () {
|
function clearOldLogs () {
|
||||||
return logs.clearOldLogs().catch(logger.error)
|
return logs.clearOldLogs()
|
||||||
|
.catch(logger.error)
|
||||||
}
|
}
|
||||||
|
|
||||||
function pong () {
|
function pong () {
|
||||||
return db
|
return db.none(`UPDATE server_events SET created=now() WHERE event_type=$1;
|
||||||
.none(
|
|
||||||
`UPDATE server_events SET created=now() WHERE event_type=$1;
|
|
||||||
INSERT INTO server_events (event_type) SELECT $1
|
INSERT INTO server_events (event_type) SELECT $1
|
||||||
WHERE NOT EXISTS (SELECT 1 FROM server_events WHERE event_type=$1);`,
|
WHERE NOT EXISTS (SELECT 1 FROM server_events WHERE event_type=$1);`, ['ping'])
|
||||||
['ping']
|
|
||||||
)
|
|
||||||
.catch(logger.error)
|
.catch(logger.error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -447,16 +409,13 @@ function plugins (settings, deviceId) {
|
||||||
const marketTradesQueues = tradesQueues[market]
|
const marketTradesQueues = tradesQueues[market]
|
||||||
if (!marketTradesQueues || marketTradesQueues.length === 0) return null
|
if (!marketTradesQueues || marketTradesQueues.length === 0) return null
|
||||||
|
|
||||||
logger.debug(
|
logger.debug('[%s] tradesQueues size: %d', market, marketTradesQueues.length)
|
||||||
'[%s] tradesQueues size: %d',
|
|
||||||
market,
|
|
||||||
marketTradesQueues.length
|
|
||||||
)
|
|
||||||
logger.debug('[%s] tradesQueues head: %j', market, marketTradesQueues[0])
|
logger.debug('[%s] tradesQueues head: %j', market, marketTradesQueues[0])
|
||||||
|
|
||||||
const t1 = Date.now()
|
const t1 = Date.now()
|
||||||
|
|
||||||
const filtered = marketTradesQueues.filter(tradeEntry => {
|
const filtered = marketTradesQueues
|
||||||
|
.filter(tradeEntry => {
|
||||||
return t1 - tradeEntry.timestamp < TRADE_TTL
|
return t1 - tradeEntry.timestamp < TRADE_TTL
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -469,14 +428,10 @@ function plugins (settings, deviceId) {
|
||||||
|
|
||||||
if (filtered.length === 0) return null
|
if (filtered.length === 0) return null
|
||||||
|
|
||||||
const cryptoAtoms = filtered.reduce(
|
const cryptoAtoms = filtered
|
||||||
(prev, current) => prev.plus(current.cryptoAtoms),
|
.reduce((prev, current) => prev.plus(current.cryptoAtoms), BN(0))
|
||||||
BN(0)
|
|
||||||
)
|
|
||||||
|
|
||||||
const timestamp = filtered
|
const timestamp = filtered.map(r => r.timestamp).reduce((acc, r) => Math.max(acc, r), 0)
|
||||||
.map(r => r.timestamp)
|
|
||||||
.reduce((acc, r) => Math.max(acc, r), 0)
|
|
||||||
|
|
||||||
const consolidatedTrade = {
|
const consolidatedTrade = {
|
||||||
fiatCode,
|
fiatCode,
|
||||||
|
|
@ -492,15 +447,11 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeTrades () {
|
function executeTrades () {
|
||||||
return machineLoader
|
return machineLoader.getMachines()
|
||||||
.getMachines()
|
|
||||||
.then(devices => {
|
.then(devices => {
|
||||||
const deviceIds = devices.map(device => device.deviceId)
|
const deviceIds = devices.map(device => device.deviceId)
|
||||||
const lists = deviceIds.map(deviceId => {
|
const lists = deviceIds.map(deviceId => {
|
||||||
const localeConfig = configManager.getLocale(
|
const localeConfig = configManager.getLocale(deviceId, settings.config)
|
||||||
deviceId,
|
|
||||||
settings.config
|
|
||||||
)
|
|
||||||
const fiatCode = localeConfig.fiatCurrency
|
const fiatCode = localeConfig.fiatCurrency
|
||||||
const cryptoCodes = localeConfig.cryptoCurrencies
|
const cryptoCodes = localeConfig.cryptoCurrencies
|
||||||
|
|
||||||
|
|
@ -510,9 +461,8 @@ function plugins (settings, deviceId) {
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
|
||||||
const tradesPromises = _.uniq(_.flatten(lists)).map(r =>
|
const tradesPromises = _.uniq(_.flatten(lists))
|
||||||
executeTradesForMarket(settings, r.fiatCode, r.cryptoCode)
|
.map(r => executeTradesForMarket(settings, r.fiatCode, r.cryptoCode))
|
||||||
)
|
|
||||||
|
|
||||||
return Promise.all(tradesPromises)
|
return Promise.all(tradesPromises)
|
||||||
})
|
})
|
||||||
|
|
@ -527,7 +477,8 @@ function plugins (settings, deviceId) {
|
||||||
|
|
||||||
if (tradeEntry === null || tradeEntry.cryptoAtoms.eq(0)) return
|
if (tradeEntry === null || tradeEntry.cryptoAtoms.eq(0)) return
|
||||||
|
|
||||||
return executeTradeForType(tradeEntry).catch(err => {
|
return executeTradeForType(tradeEntry)
|
||||||
|
.catch(err => {
|
||||||
tradesQueues[market].push(tradeEntry)
|
tradesQueues[market].push(tradeEntry)
|
||||||
if (err.name === 'orderTooSmall') return logger.debug(err.message)
|
if (err.name === 'orderTooSmall') return logger.debug(err.message)
|
||||||
logger.error(err)
|
logger.error(err)
|
||||||
|
|
@ -535,8 +486,7 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeTradeForType (_tradeEntry) {
|
function executeTradeForType (_tradeEntry) {
|
||||||
const expand = te =>
|
const expand = te => _.assign(te, {
|
||||||
_.assign(te, {
|
|
||||||
cryptoAtoms: te.cryptoAtoms.abs(),
|
cryptoAtoms: te.cryptoAtoms.abs(),
|
||||||
type: te.cryptoAtoms.gte(0) ? 'buy' : 'sell'
|
type: te.cryptoAtoms.gte(0) ? 'buy' : 'sell'
|
||||||
})
|
})
|
||||||
|
|
@ -544,26 +494,24 @@ function plugins (settings, deviceId) {
|
||||||
const tradeEntry = expand(_tradeEntry)
|
const tradeEntry = expand(_tradeEntry)
|
||||||
const execute = tradeEntry.type === 'buy' ? exchange.buy : exchange.sell
|
const execute = tradeEntry.type === 'buy' ? exchange.buy : exchange.sell
|
||||||
|
|
||||||
return execute(
|
return execute(settings, tradeEntry.cryptoAtoms, tradeEntry.fiatCode, tradeEntry.cryptoCode)
|
||||||
settings,
|
|
||||||
tradeEntry.cryptoAtoms,
|
|
||||||
tradeEntry.fiatCode,
|
|
||||||
tradeEntry.cryptoCode
|
|
||||||
)
|
|
||||||
.then(() => recordTrade(tradeEntry))
|
.then(() => recordTrade(tradeEntry))
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
return recordTrade(tradeEntry, err).then(() => {
|
return recordTrade(tradeEntry, err)
|
||||||
|
.then(() => {
|
||||||
throw err
|
throw err
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertBigNumFields (obj) {
|
function convertBigNumFields (obj) {
|
||||||
const convert = (value, key) =>
|
const convert = (value, key) => _.includes(key, ['cryptoAtoms', 'fiat'])
|
||||||
_.includes(key, ['cryptoAtoms', 'fiat']) ? value.toString() : value
|
? value.toString()
|
||||||
|
: value
|
||||||
|
|
||||||
const convertKey = key =>
|
const convertKey = key => _.includes(key, ['cryptoAtoms', 'fiat'])
|
||||||
_.includes(key, ['cryptoAtoms', 'fiat']) ? key + '#' : key
|
? key + '#'
|
||||||
|
: key
|
||||||
|
|
||||||
return _.mapKeys(convertKey, mapValuesWithKey(convert, obj))
|
return _.mapKeys(convertKey, mapValuesWithKey(convert, obj))
|
||||||
}
|
}
|
||||||
|
|
@ -604,24 +552,16 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkDeviceCashBalances (fiatCode, device) {
|
function checkDeviceCashBalances (fiatCode, device) {
|
||||||
const cashOutConfig = configManager.getCashOut(
|
const cashOutConfig = configManager.getCashOut(device.deviceId, settings.config)
|
||||||
device.deviceId,
|
|
||||||
settings.config
|
|
||||||
)
|
|
||||||
const denomination1 = cashOutConfig.top
|
const denomination1 = cashOutConfig.top
|
||||||
const denomination2 = cashOutConfig.bottom
|
const denomination2 = cashOutConfig.bottom
|
||||||
const cashOutEnabled = cashOutConfig.active
|
const cashOutEnabled = cashOutConfig.active
|
||||||
|
|
||||||
const notifications = configManager.getNotifications(
|
const notifications = configManager.getNotifications(null, device.deviceId, settings.config)
|
||||||
null,
|
|
||||||
device.deviceId,
|
|
||||||
settings.config
|
|
||||||
)
|
|
||||||
|
|
||||||
const machineName = device.name
|
const machineName = device.name
|
||||||
|
|
||||||
const cashInAlert =
|
const cashInAlert = device.cashbox > notifications.cashInAlertThreshold
|
||||||
device.cashbox > notifications.cashInAlertThreshold
|
|
||||||
? {
|
? {
|
||||||
code: 'CASH_BOX_FULL',
|
code: 'CASH_BOX_FULL',
|
||||||
machineName,
|
machineName,
|
||||||
|
|
@ -630,8 +570,7 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
|
|
||||||
const cassette1Alert =
|
const cassette1Alert = cashOutEnabled && device.cassette1 < notifications.fiatBalanceCassette1
|
||||||
cashOutEnabled && device.cassette1 < notifications.fiatBalanceCassette1
|
|
||||||
? {
|
? {
|
||||||
code: 'LOW_CASH_OUT',
|
code: 'LOW_CASH_OUT',
|
||||||
cassette: 1,
|
cassette: 1,
|
||||||
|
|
@ -643,8 +582,7 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
|
|
||||||
const cassette2Alert =
|
const cassette2Alert = cashOutEnabled && device.cassette2 < notifications.fiatBalanceCassette2
|
||||||
cashOutEnabled && device.cassette2 < notifications.fiatBalanceCassette2
|
|
||||||
? {
|
? {
|
||||||
code: 'LOW_CASH_OUT',
|
code: 'LOW_CASH_OUT',
|
||||||
cassette: 2,
|
cassette: 2,
|
||||||
|
|
@ -660,8 +598,7 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkCryptoBalances (fiatCode, devices) {
|
function checkCryptoBalances (fiatCode, devices) {
|
||||||
const fiatBalancePromises = cryptoCodes =>
|
const fiatBalancePromises = cryptoCodes => _.map(c => fiatBalance(fiatCode, c), cryptoCodes)
|
||||||
_.map(c => fiatBalance(fiatCode, c), cryptoCodes)
|
|
||||||
|
|
||||||
const fetchCryptoCodes = _deviceId => {
|
const fetchCryptoCodes = _deviceId => {
|
||||||
const localeConfig = configManager.getLocale(_deviceId, settings.config)
|
const localeConfig = configManager.getLocale(_deviceId, settings.config)
|
||||||
|
|
@ -672,20 +609,15 @@ function plugins (settings, deviceId) {
|
||||||
const cryptoCodes = union(devices)
|
const cryptoCodes = union(devices)
|
||||||
const checkCryptoBalanceWithFiat = _.partial(checkCryptoBalance, [fiatCode])
|
const checkCryptoBalanceWithFiat = _.partial(checkCryptoBalance, [fiatCode])
|
||||||
|
|
||||||
return Promise.all(fiatBalancePromises(cryptoCodes)).then(balances =>
|
return Promise.all(fiatBalancePromises(cryptoCodes))
|
||||||
_.map(checkCryptoBalanceWithFiat, _.zip(cryptoCodes, balances))
|
.then(balances => _.map(checkCryptoBalanceWithFiat, _.zip(cryptoCodes, balances)))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkCryptoBalance (fiatCode, rec) {
|
function checkCryptoBalance (fiatCode, rec) {
|
||||||
const [cryptoCode, fiatBalance] = rec
|
const [cryptoCode, fiatBalance] = rec
|
||||||
if (!fiatBalance) return null
|
if (!fiatBalance) return null
|
||||||
|
|
||||||
const notifications = configManager.getNotifications(
|
const notifications = configManager.getNotifications(cryptoCode, null, settings.config)
|
||||||
cryptoCode,
|
|
||||||
null,
|
|
||||||
settings.config
|
|
||||||
)
|
|
||||||
const lowAlertThreshold = notifications.cryptoLowBalance
|
const lowAlertThreshold = notifications.cryptoLowBalance
|
||||||
const highAlertThreshold = notifications.cryptoHighBalance
|
const highAlertThreshold = notifications.cryptoHighBalance
|
||||||
|
|
||||||
|
|
@ -710,23 +642,24 @@ function plugins (settings, deviceId) {
|
||||||
const localeConfig = configManager.getGlobalLocale(settings.config)
|
const localeConfig = configManager.getGlobalLocale(settings.config)
|
||||||
const fiatCode = localeConfig.fiatCurrency
|
const fiatCode = localeConfig.fiatCurrency
|
||||||
|
|
||||||
return machineLoader.getMachines().then(devices => {
|
return machineLoader.getMachines()
|
||||||
|
.then(devices => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
checkCryptoBalances(fiatCode, devices),
|
checkCryptoBalances(fiatCode, devices),
|
||||||
checkDevicesCashBalances(fiatCode, devices)
|
checkDevicesCashBalances(fiatCode, devices)
|
||||||
]).then(_.flow(_.flattenDeep, _.compact))
|
])
|
||||||
|
.then(_.flow(_.flattenDeep, _.compact))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function randomCode () {
|
function randomCode () {
|
||||||
return BN(crypto.randomBytes(3).toString('hex'), 16)
|
return BN(crypto.randomBytes(3).toString('hex'), 16).shift(-6).toFixed(6).slice(-6)
|
||||||
.shift(-6)
|
|
||||||
.toFixed(6)
|
|
||||||
.slice(-6)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPhoneCode (phone) {
|
function getPhoneCode (phone) {
|
||||||
const code = argv.mockSms ? '123' : randomCode()
|
const code = argv.mockSms
|
||||||
|
? '123'
|
||||||
|
: randomCode()
|
||||||
|
|
||||||
const rec = {
|
const rec = {
|
||||||
sms: {
|
sms: {
|
||||||
|
|
@ -735,14 +668,14 @@ function plugins (settings, deviceId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sms.sendMessage(settings, rec).then(() => code)
|
return sms.sendMessage(settings, rec)
|
||||||
|
.then(() => code)
|
||||||
}
|
}
|
||||||
|
|
||||||
function sweepHdRow (row) {
|
function sweepHdRow (row) {
|
||||||
const cryptoCode = row.crypto_code
|
const cryptoCode = row.crypto_code
|
||||||
|
|
||||||
return wallet
|
return wallet.sweep(settings, cryptoCode, row.hd_index)
|
||||||
.sweep(settings, cryptoCode, row.hd_index)
|
|
||||||
.then(txHash => {
|
.then(txHash => {
|
||||||
if (txHash) {
|
if (txHash) {
|
||||||
logger.debug('[%s] Swept address with tx: %s', cryptoCode, txHash)
|
logger.debug('[%s] Swept address with tx: %s', cryptoCode, txHash)
|
||||||
|
|
@ -753,17 +686,14 @@ function plugins (settings, deviceId) {
|
||||||
return db.none(sql, row.id)
|
return db.none(sql, row.id)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(err =>
|
.catch(err => logger.error('[%s] Sweep error: %s', cryptoCode, err.message))
|
||||||
logger.error('[%s] Sweep error: %s', cryptoCode, err.message)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sweepHd () {
|
function sweepHd () {
|
||||||
const sql = `select id, crypto_code, hd_index from cash_out_txs
|
const sql = `select id, crypto_code, hd_index from cash_out_txs
|
||||||
where hd_index is not null and not swept and status in ('confirmed', 'instant')`
|
where hd_index is not null and not swept and status in ('confirmed', 'instant')`
|
||||||
|
|
||||||
return db
|
return db.any(sql)
|
||||||
.any(sql)
|
|
||||||
.then(rows => Promise.all(rows.map(sweepHdRow)))
|
.then(rows => Promise.all(rows.map(sweepHdRow)))
|
||||||
.catch(err => logger.error(err))
|
.catch(err => logger.error(err))
|
||||||
}
|
}
|
||||||
|
|
@ -777,15 +707,14 @@ function plugins (settings, deviceId) {
|
||||||
const fiatCode = localeConfig.fiatCurrency
|
const fiatCode = localeConfig.fiatCurrency
|
||||||
|
|
||||||
const cryptoCodes = configManager.getAllCryptoCurrencies(settings.config)
|
const cryptoCodes = configManager.getAllCryptoCurrencies(settings.config)
|
||||||
const tickerPromises = cryptoCodes.map(c =>
|
const tickerPromises = cryptoCodes.map(c => ticker.getRates(settings, fiatCode, c))
|
||||||
ticker.getRates(settings, fiatCode, c)
|
|
||||||
)
|
|
||||||
|
|
||||||
return Promise.all(tickerPromises)
|
return Promise.all(tickerPromises)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRates () {
|
function getRates () {
|
||||||
return getRawRates().then(buildRates)
|
return getRawRates()
|
||||||
|
.then(buildRates)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
const plugins = require('./plugins')
|
const plugins = require('./plugins')
|
||||||
const notifier = require('./notifier/index')
|
const notifier = require('./notifier')
|
||||||
const T = require('./time')
|
const T = require('./time')
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
const cashOutTx = require('./cash-out/cash-out-tx')
|
const cashOutTx = require('./cash-out/cash-out-tx')
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,6 @@ function updateCustomer (req, res, next) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function triggerSanctions (req, res, next) {
|
function triggerSanctions (req, res, next) {
|
||||||
console.log("SANCTIONS TRIGGERED")
|
|
||||||
const id = req.params.id
|
const id = req.params.id
|
||||||
|
|
||||||
customers.getById(id)
|
customers.getById(id)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ const mem = require('mem')
|
||||||
const configManager = require('./new-config-manager')
|
const configManager = require('./new-config-manager')
|
||||||
const ph = require('./plugin-helper')
|
const ph = require('./plugin-helper')
|
||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
const axios = require('axios')
|
|
||||||
|
|
||||||
const lastRate = {}
|
const lastRate = {}
|
||||||
|
|
||||||
|
|
@ -40,26 +39,4 @@ const getRates = mem(_getRates, {
|
||||||
cacheKey: (settings, fiatCode, cryptoCode) => JSON.stringify([fiatCode, cryptoCode])
|
cacheKey: (settings, fiatCode, cryptoCode) => JSON.stringify([fiatCode, cryptoCode])
|
||||||
})
|
})
|
||||||
|
|
||||||
const getBtcRates = (to = null, from = 'USD') => {
|
module.exports = { getRates }
|
||||||
// if to !== null, then we return only the rates with from (default USD) and to (so an array with 2 items)
|
|
||||||
return axios.get('https://bitpay.com/api/rates').then(response => {
|
|
||||||
const fxRates = response.data
|
|
||||||
if (to === null) {
|
|
||||||
return fxRates
|
|
||||||
}
|
|
||||||
const toRate = fxRates.find(o => o.code === to)
|
|
||||||
const fromRate = fxRates.find(o => o.code === from)
|
|
||||||
|
|
||||||
let res = []
|
|
||||||
if (toRate && to !== from) {
|
|
||||||
res = [...res, toRate]
|
|
||||||
}
|
|
||||||
if (fromRate) {
|
|
||||||
res = [...res, fromRate]
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { getBtcRates, getRates }
|
|
||||||
|
|
|
||||||
42418
new-lamassu-admin/package-lock.json
generated
42418
new-lamassu-admin/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -91,7 +91,6 @@ const TL2 = pBuilder('tl2')
|
||||||
const Label1 = pBuilder('label1')
|
const Label1 = pBuilder('label1')
|
||||||
const Label2 = pBuilder('label2')
|
const Label2 = pBuilder('label2')
|
||||||
const Label3 = pBuilder('label3')
|
const Label3 = pBuilder('label3')
|
||||||
const Label4 = pBuilder('regularLabel')
|
|
||||||
|
|
||||||
function pBuilder(elementClass) {
|
function pBuilder(elementClass) {
|
||||||
return ({ inline, noMargin, className, children, ...props }) => {
|
return ({ inline, noMargin, className, children, ...props }) => {
|
||||||
|
|
@ -125,6 +124,5 @@ export {
|
||||||
Mono,
|
Mono,
|
||||||
Label1,
|
Label1,
|
||||||
Label2,
|
Label2,
|
||||||
Label3,
|
Label3
|
||||||
Label4
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ const base = {
|
||||||
color: fontColor
|
color: fontColor
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = {
|
export default {
|
||||||
h1: {
|
h1: {
|
||||||
extend: base,
|
extend: base,
|
||||||
fontSize: fontSize1,
|
fontSize: fontSize1,
|
||||||
|
|
@ -132,5 +132,3 @@ const styles = {
|
||||||
margin: 0
|
margin: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default styles
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import {
|
||||||
TransactionsList,
|
TransactionsList,
|
||||||
ComplianceDetails
|
ComplianceDetails
|
||||||
} from './components'
|
} from './components'
|
||||||
import { /* getFormattedPhone, */ getName } from './helper'
|
import { getFormattedPhone, getName } from './helper'
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
|
@ -147,13 +147,12 @@ const CustomerProfile = memo(() => {
|
||||||
Customers
|
Customers
|
||||||
</Label1>
|
</Label1>
|
||||||
<Label2 noMargin className={classes.labelLink}>
|
<Label2 noMargin className={classes.labelLink}>
|
||||||
{name.length ? name : R.path(['phone'])(customerData)}
|
{name.length
|
||||||
{/* {name.length
|
|
||||||
? name
|
? name
|
||||||
: getFormattedPhone(
|
: getFormattedPhone(
|
||||||
R.path(['phone'])(customerData),
|
R.path(['phone'])(customerData),
|
||||||
locale.country
|
locale.country
|
||||||
)} */}
|
)}
|
||||||
</Label2>
|
</Label2>
|
||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,7 @@ import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-ou
|
||||||
import { ifNotNull } from 'src/utils/nullCheck'
|
import { ifNotNull } from 'src/utils/nullCheck'
|
||||||
|
|
||||||
import styles from './CustomersList.styles'
|
import styles from './CustomersList.styles'
|
||||||
import {
|
import { getAuthorizedStatus, getFormattedPhone, getName } from './helper'
|
||||||
getAuthorizedStatus,
|
|
||||||
getName
|
|
||||||
/* getFormattedPhone */
|
|
||||||
} from './helper'
|
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
|
@ -26,7 +22,7 @@ const CustomersList = ({ data, locale, onClick, loading }) => {
|
||||||
{
|
{
|
||||||
header: 'Phone',
|
header: 'Phone',
|
||||||
width: 172,
|
width: 172,
|
||||||
view: it => it.phone // getFormattedPhone(it.phone, locale.country)
|
view: it => getFormattedPhone(it.phone, locale.country)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Name',
|
header: 'Name',
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { ReactComponent as LawIconInverse } from 'src/styling/icons/circle butto
|
||||||
import { ReactComponent as LawIcon } from 'src/styling/icons/circle buttons/law/zodiac.svg'
|
import { ReactComponent as LawIcon } from 'src/styling/icons/circle buttons/law/zodiac.svg'
|
||||||
|
|
||||||
import mainStyles from '../CustomersList.styles'
|
import mainStyles from '../CustomersList.styles'
|
||||||
import { /* getFormattedPhone, */ getName } from '../helper'
|
import { getFormattedPhone, getName } from '../helper'
|
||||||
|
|
||||||
import FrontCameraPhoto from './FrontCameraPhoto'
|
import FrontCameraPhoto from './FrontCameraPhoto'
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@ const CustomerDetails = memo(({ customer, locale, setShowCompliance }) => {
|
||||||
{
|
{
|
||||||
header: 'Phone number',
|
header: 'Phone number',
|
||||||
size: 172,
|
size: 172,
|
||||||
value: customer.phone // getFormattedPhone(customer.phone, locale.country)
|
value: getFormattedPhone(customer.phone, locale.country)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'ID number',
|
header: 'ID number',
|
||||||
|
|
@ -47,8 +47,9 @@ const CustomerDetails = memo(({ customer, locale, setShowCompliance }) => {
|
||||||
<div className={classes.name}>
|
<div className={classes.name}>
|
||||||
<IdIcon className={classes.idIcon} />
|
<IdIcon className={classes.idIcon} />
|
||||||
<H2 noMargin>
|
<H2 noMargin>
|
||||||
{name.length ? name : R.path(['phone'])(customer)}
|
{name.length
|
||||||
{/* getFormattedPhone(R.path(['phone'])(customer), locale.country)} */}
|
? name
|
||||||
|
: getFormattedPhone(R.path(['phone'])(customer), locale.country)}
|
||||||
</H2>
|
</H2>
|
||||||
<SubpageButton
|
<SubpageButton
|
||||||
className={classes.subpageButton}
|
className={classes.subpageButton}
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,10 @@ const getAuthorizedStatus = it =>
|
||||||
: { label: 'Authorized', type: 'success' }
|
: { label: 'Authorized', type: 'success' }
|
||||||
|
|
||||||
const getFormattedPhone = (phone, country) => {
|
const getFormattedPhone = (phone, country) => {
|
||||||
return phone && country
|
const phoneNumber =
|
||||||
? parsePhoneNumberFromString(phone, country).formatInternational()
|
phone && country ? parsePhoneNumberFromString(phone, country) : null
|
||||||
: ''
|
|
||||||
|
return phoneNumber ? phoneNumber.formatInternational() : phone
|
||||||
}
|
}
|
||||||
|
|
||||||
const getName = it => {
|
const getName = it => {
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,7 @@ const Alerts = ({ onReset, onExpand, size }) => {
|
||||||
{showAllItems && (
|
{showAllItems && (
|
||||||
<Label1 className={classes.upperButtonLabel}>
|
<Label1 className={classes.upperButtonLabel}>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={onReset}
|
||||||
console.log('aaaa')
|
|
||||||
onReset()
|
|
||||||
}}
|
|
||||||
size="small"
|
size="small"
|
||||||
disableRipple
|
disableRipple
|
||||||
disableFocusRipple
|
disableFocusRipple
|
||||||
|
|
|
||||||
|
|
@ -31,42 +31,49 @@ const styles = {
|
||||||
other: {
|
other: {
|
||||||
minWidth: '6px',
|
minWidth: '6px',
|
||||||
borderRadius: 2
|
borderRadius: 2
|
||||||
|
},
|
||||||
|
inWidth: {
|
||||||
|
width: value => `${value}%`
|
||||||
|
},
|
||||||
|
outWidth: {
|
||||||
|
width: value => `${100 - value}%`,
|
||||||
|
marginRight: 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
const PercentageChart = ({ cashIn, cashOut }) => {
|
const PercentageChart = ({ cashIn, cashOut }) => {
|
||||||
const classes = useStyles()
|
|
||||||
const value = cashIn || cashOut !== 0 ? cashIn : 50
|
const value = cashIn || cashOut !== 0 ? cashIn : 50
|
||||||
|
const classes = useStyles(value)
|
||||||
|
|
||||||
const buildPercentageView = value => {
|
const buildPercentageView = value => {
|
||||||
if (value > 15) {
|
if (value <= 15) return
|
||||||
return <Label1 className={classes.label}>{` ${value}%`}</Label1>
|
return <Label1 className={classes.label}>{value}%</Label1>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const percentageClasses = {
|
||||||
|
[classes.percentageBox]: true,
|
||||||
|
[classes.other]: value < 5 && value > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.wrapper}>
|
<div className={classes.wrapper}>
|
||||||
<div
|
<div
|
||||||
className={classnames(
|
className={classnames(
|
||||||
classes.percentageBox,
|
percentageClasses,
|
||||||
classes.inColor,
|
classes.outColor,
|
||||||
// if value between [1, 4], percentage box should not go below 6 px and border radius is 2px
|
classes.outWidth
|
||||||
// if value is 0 or 100, then width will be allowed to be 0px in one of the boxes, making it disappear
|
)}>
|
||||||
value < 5 && value > 0 ? classes.other : null
|
{buildPercentageView(100 - value, 'cashOut')}
|
||||||
)}
|
|
||||||
style={{ width: `${value}%`, marginRight: 4 }}>
|
|
||||||
{buildPercentageView(value, 'cashIn')}
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={classnames(
|
className={classnames(
|
||||||
classes.percentageBox,
|
percentageClasses,
|
||||||
classes.outColor,
|
classes.inColor,
|
||||||
100 - value < 5 && 100 - value > 0 ? classes.other : null
|
classes.inWidth
|
||||||
)}
|
)}>
|
||||||
style={{ width: `${100 - value}%` }}>
|
{buildPercentageView(value, 'cashIn')}
|
||||||
{buildPercentageView(100 - value, 'cashOut')}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
|
||||||
import classnames from 'classnames'
|
|
||||||
import * as R from 'ramda'
|
|
||||||
import React, { useState, useEffect } from 'react'
|
|
||||||
import { CopyToClipboard as ReactCopyToClipboard } from 'react-copy-to-clipboard'
|
|
||||||
|
|
||||||
import Popover from 'src/components/Popper'
|
|
||||||
import { ReactComponent as CopyIcon } from 'src/styling/icons/action/copy/copy.svg'
|
|
||||||
import { comet } from 'src/styling/variables'
|
|
||||||
|
|
||||||
import { cpcStyles } from './Transactions.styles'
|
|
||||||
|
|
||||||
const useStyles = makeStyles(cpcStyles)
|
|
||||||
|
|
||||||
const CopyToClipboard = ({
|
|
||||||
className,
|
|
||||||
buttonClassname,
|
|
||||||
children,
|
|
||||||
...props
|
|
||||||
}) => {
|
|
||||||
const [anchorEl, setAnchorEl] = useState(null)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (anchorEl) setTimeout(() => setAnchorEl(null), 3000)
|
|
||||||
}, [anchorEl])
|
|
||||||
|
|
||||||
const classes = useStyles()
|
|
||||||
|
|
||||||
const handleClick = event => {
|
|
||||||
setAnchorEl(anchorEl ? null : event.currentTarget)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
setAnchorEl(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
const open = Boolean(anchorEl)
|
|
||||||
const id = open ? 'simple-popper' : undefined
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.wrapper}>
|
|
||||||
{children && (
|
|
||||||
<>
|
|
||||||
<div className={classnames(classes.address, className)}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
<div className={classnames(classes.buttonWrapper, buttonClassname)}>
|
|
||||||
<ReactCopyToClipboard text={R.replace(/\s/g, '')(children)}>
|
|
||||||
<button
|
|
||||||
aria-describedby={id}
|
|
||||||
onClick={event => handleClick(event)}>
|
|
||||||
<CopyIcon />
|
|
||||||
</button>
|
|
||||||
</ReactCopyToClipboard>
|
|
||||||
</div>
|
|
||||||
<Popover
|
|
||||||
id={id}
|
|
||||||
open={open}
|
|
||||||
anchorEl={anchorEl}
|
|
||||||
onClose={handleClose}
|
|
||||||
arrowSize={3}
|
|
||||||
bgColor={comet}
|
|
||||||
placement="top">
|
|
||||||
<div className={classes.popoverContent}>
|
|
||||||
<div>Copied to clipboard!</div>
|
|
||||||
</div>
|
|
||||||
</Popover>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CopyToClipboard
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
import { zircon } from 'src/styling/variables'
|
|
||||||
|
|
||||||
const styles = {
|
|
||||||
expandButton: {
|
|
||||||
outline: 'none',
|
|
||||||
border: 'none',
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
cursor: 'pointer',
|
|
||||||
padding: 4
|
|
||||||
},
|
|
||||||
rowWrapper: {
|
|
||||||
// workaround to shadows cut by r-virtualized when scroll is visible
|
|
||||||
padding: 1
|
|
||||||
},
|
|
||||||
row: {
|
|
||||||
border: [[2, 'solid', 'transparent']],
|
|
||||||
borderRadius: 0
|
|
||||||
},
|
|
||||||
expanded: {
|
|
||||||
border: [[2, 'solid', zircon]],
|
|
||||||
boxShadow: '0 0 8px 0 rgba(0,0,0,0.08)'
|
|
||||||
},
|
|
||||||
before: {
|
|
||||||
paddingTop: 12
|
|
||||||
},
|
|
||||||
after: {
|
|
||||||
paddingBottom: 12
|
|
||||||
},
|
|
||||||
pointer: {
|
|
||||||
cursor: 'pointer'
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
flex: [[1, 1, 'auto']]
|
|
||||||
},
|
|
||||||
table: ({ width }) => ({
|
|
||||||
marginBottom: 30,
|
|
||||||
minHeight: 200,
|
|
||||||
width,
|
|
||||||
flex: 1,
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export default styles
|
|
||||||
|
|
@ -1,195 +0,0 @@
|
||||||
import { makeStyles, Box } from '@material-ui/core'
|
|
||||||
import BigNumber from 'bignumber.js'
|
|
||||||
import moment from 'moment'
|
|
||||||
import React, { memo } from 'react'
|
|
||||||
|
|
||||||
import { IDButton } from 'src/components/buttons'
|
|
||||||
import { Label1 } from 'src/components/typography'
|
|
||||||
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 PhoneIdInverseIcon } from 'src/styling/icons/ID/phone/white.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 CamIdIcon } from 'src/styling/icons/ID/photo/zodiac.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 { URI } from 'src/utils/apollo'
|
|
||||||
import { toUnit, formatCryptoAddress } from 'src/utils/coin'
|
|
||||||
import { onlyFirstToUpper } from 'src/utils/string'
|
|
||||||
|
|
||||||
import CopyToClipboard from './CopyToClipboard'
|
|
||||||
import styles from './DetailsCard.styles'
|
|
||||||
import { getStatus } from './helper'
|
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
|
||||||
|
|
||||||
const formatAddress = (cryptoCode = '', address = '') =>
|
|
||||||
formatCryptoAddress(cryptoCode, address).replace(/(.{5})/g, '$1 ')
|
|
||||||
|
|
||||||
const Label = ({ children }) => {
|
|
||||||
const classes = useStyles()
|
|
||||||
return <Label1 className={classes.label}>{children}</Label1>
|
|
||||||
}
|
|
||||||
|
|
||||||
const DetailsRow = ({ it: tx }) => {
|
|
||||||
const classes = useStyles()
|
|
||||||
|
|
||||||
const fiat = Number.parseFloat(tx.fiat)
|
|
||||||
const crypto = toUnit(new BigNumber(tx.cryptoAtoms), tx.cryptoCode)
|
|
||||||
const commissionPercentage = Number.parseFloat(tx.commissionPercentage, 2)
|
|
||||||
const commission = Number(fiat * commissionPercentage).toFixed(2)
|
|
||||||
const exchangeRate = Number(fiat / crypto).toFixed(3)
|
|
||||||
const displayExRate = `1 ${tx.cryptoCode} = ${exchangeRate} ${tx.fiatCode}`
|
|
||||||
|
|
||||||
const customer = tx.customerIdCardData && {
|
|
||||||
name: `${onlyFirstToUpper(
|
|
||||||
tx.customerIdCardData.firstName
|
|
||||||
)} ${onlyFirstToUpper(tx.customerIdCardData.lastName)}`,
|
|
||||||
age: moment().diff(moment(tx.customerIdCardData.dateOfBirth), 'years'),
|
|
||||||
country: tx.customerIdCardData.country,
|
|
||||||
idCardNumber: tx.customerIdCardData.documentNumber,
|
|
||||||
idCardExpirationDate: moment(tx.customerIdCardData.expirationDate).format(
|
|
||||||
'DD-MM-YYYY'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.wrapper}>
|
|
||||||
<div className={classes.row}>
|
|
||||||
<div className={classes.direction}>
|
|
||||||
<Label>Direction</Label>
|
|
||||||
<div>
|
|
||||||
<span className={classes.txIcon}>
|
|
||||||
{tx.txClass === 'cashOut' ? <TxOutIcon /> : <TxInIcon />}
|
|
||||||
</span>
|
|
||||||
<span>{tx.txClass === 'cashOut' ? 'Cash-out' : 'Cash-in'}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classes.availableIds}>
|
|
||||||
<Label>Available IDs</Label>
|
|
||||||
<Box display="flex" flexDirection="row">
|
|
||||||
{tx.customerPhone && (
|
|
||||||
<IDButton
|
|
||||||
className={classes.idButton}
|
|
||||||
name="phone"
|
|
||||||
Icon={PhoneIdIcon}
|
|
||||||
InverseIcon={PhoneIdInverseIcon}>
|
|
||||||
{tx.customerPhone}
|
|
||||||
</IDButton>
|
|
||||||
)}
|
|
||||||
{tx.customerIdCardPhotoPath && !tx.customerIdCardData && (
|
|
||||||
<IDButton
|
|
||||||
popoverClassname={classes.popover}
|
|
||||||
className={classes.idButton}
|
|
||||||
name="card"
|
|
||||||
Icon={CardIdIcon}
|
|
||||||
InverseIcon={CardIdInverseIcon}>
|
|
||||||
<img
|
|
||||||
className={classes.idCardPhoto}
|
|
||||||
src={`${URI}/id-card-photo/${tx.customerIdCardPhotoPath}`}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
</IDButton>
|
|
||||||
)}
|
|
||||||
{tx.customerIdCardData && (
|
|
||||||
<IDButton
|
|
||||||
className={classes.idButton}
|
|
||||||
name="card"
|
|
||||||
Icon={CardIdIcon}
|
|
||||||
InverseIcon={CardIdInverseIcon}>
|
|
||||||
<div className={classes.idCardDataCard}>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<Label>Name</Label>
|
|
||||||
<div>{customer.name}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label>Age</Label>
|
|
||||||
<div>{customer.age}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label>Country</Label>
|
|
||||||
<div>{customer.country}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<Label>ID number</Label>
|
|
||||||
<div>{customer.idCardNumber}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label>Expiration date</Label>
|
|
||||||
<div>{customer.idCardExpirationDate}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</IDButton>
|
|
||||||
)}
|
|
||||||
{tx.customerFrontCameraPath && (
|
|
||||||
<IDButton
|
|
||||||
name="cam"
|
|
||||||
Icon={CamIdIcon}
|
|
||||||
InverseIcon={CamIdInverseIcon}>
|
|
||||||
<img
|
|
||||||
src={`${URI}/front-camera-photo/${tx.customerFrontCameraPath}`}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
</IDButton>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</div>
|
|
||||||
<div className={classes.exchangeRate}>
|
|
||||||
<Label>Exchange rate</Label>
|
|
||||||
<div>{crypto > 0 ? displayExRate : '-'}</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.commission}>
|
|
||||||
<Label>Commission</Label>
|
|
||||||
<div>
|
|
||||||
{`${commission} ${tx.fiatCode} (${commissionPercentage * 100} %)`}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label>Fixed fee</Label>
|
|
||||||
<div>
|
|
||||||
{tx.txClass === 'cashIn'
|
|
||||||
? `${Number.parseFloat(tx.cashInFee)} ${tx.fiatCode}`
|
|
||||||
: 'N/A'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.secondRow}>
|
|
||||||
<div className={classes.address}>
|
|
||||||
<Label>Address</Label>
|
|
||||||
<div>
|
|
||||||
<CopyToClipboard>
|
|
||||||
{formatAddress(tx.cryptoCode, tx.toAddress)}
|
|
||||||
</CopyToClipboard>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.transactionId}>
|
|
||||||
<Label>Transaction ID</Label>
|
|
||||||
<div>
|
|
||||||
{tx.txClass === 'cashOut' ? (
|
|
||||||
'N/A'
|
|
||||||
) : (
|
|
||||||
<CopyToClipboard>{tx.txHash}</CopyToClipboard>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.sessionId}>
|
|
||||||
<Label>Session ID</Label>
|
|
||||||
<CopyToClipboard>{tx.id}</CopyToClipboard>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.lastRow}>
|
|
||||||
<div>
|
|
||||||
<Label>Transaction status</Label>
|
|
||||||
<span className={classes.bold}>{getStatus(tx)}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default memo(DetailsRow, (prev, next) => prev.id === next.id)
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
import typographyStyles from 'src/components/typography/styles'
|
|
||||||
import { offColor } from 'src/styling/variables'
|
|
||||||
|
|
||||||
const { p } = typographyStyles
|
|
||||||
|
|
||||||
const styles = {
|
|
||||||
wrapper: {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
marginTop: 24
|
|
||||||
},
|
|
||||||
row: {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
marginBottom: 36
|
|
||||||
},
|
|
||||||
secondRow: {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
marginBottom: 36
|
|
||||||
},
|
|
||||||
lastRow: {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
marginBottom: 32
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
color: offColor,
|
|
||||||
margin: [[0, 0, 6, 0]]
|
|
||||||
},
|
|
||||||
txIcon: {
|
|
||||||
marginRight: 10
|
|
||||||
},
|
|
||||||
popover: {
|
|
||||||
height: 164,
|
|
||||||
width: 215
|
|
||||||
},
|
|
||||||
idButton: {
|
|
||||||
marginRight: 4
|
|
||||||
},
|
|
||||||
idCardDataCard: {
|
|
||||||
extend: p,
|
|
||||||
display: 'flex',
|
|
||||||
padding: [[11, 8]],
|
|
||||||
// rework this into a proper component
|
|
||||||
'& > div': {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
'& > div': {
|
|
||||||
width: 144,
|
|
||||||
height: 37,
|
|
||||||
marginBottom: 15,
|
|
||||||
'&:last-child': {
|
|
||||||
marginBottom: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
bold: {
|
|
||||||
fontWeight: 700
|
|
||||||
},
|
|
||||||
direction: {
|
|
||||||
width: 233
|
|
||||||
},
|
|
||||||
availableIds: {
|
|
||||||
width: 232
|
|
||||||
},
|
|
||||||
exchangeRate: {
|
|
||||||
width: 250
|
|
||||||
},
|
|
||||||
commission: {
|
|
||||||
width: 217
|
|
||||||
},
|
|
||||||
address: {
|
|
||||||
width: 280
|
|
||||||
},
|
|
||||||
transactionId: {
|
|
||||||
width: 280
|
|
||||||
},
|
|
||||||
sessionId: {
|
|
||||||
width: 215
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default styles
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import { Td } from 'src/components/fake-table/Table'
|
|
||||||
import { ReactComponent as StripesSvg } from 'src/styling/icons/stripes.svg'
|
|
||||||
|
|
||||||
const Stripes = ({ width }) => (
|
|
||||||
<Td width={width}>
|
|
||||||
<StripesSvg />
|
|
||||||
</Td>
|
|
||||||
)
|
|
||||||
|
|
||||||
export default Stripes
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
const getCashOutStatus = it => {
|
|
||||||
if (it.hasError) return 'Error'
|
|
||||||
if (it.dispense) return 'Success'
|
|
||||||
if (it.expired) return 'Expired'
|
|
||||||
return 'Pending'
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCashInStatus = it => {
|
|
||||||
if (it.operatorCompleted) return 'Cancelled'
|
|
||||||
if (it.hasError) return 'Error'
|
|
||||||
if (it.sendConfirmed) return 'Sent'
|
|
||||||
if (it.expired) return 'Expired'
|
|
||||||
return 'Pending'
|
|
||||||
}
|
|
||||||
|
|
||||||
const getStatus = it => {
|
|
||||||
if (it.class === 'cashOut') {
|
|
||||||
return getCashOutStatus(it)
|
|
||||||
}
|
|
||||||
return getCashInStatus(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
export { getStatus }
|
|
||||||
|
|
@ -9,8 +9,8 @@ import { transformNumber } from 'src/utils/number'
|
||||||
|
|
||||||
import NotificationsCtx from '../NotificationsContext'
|
import NotificationsCtx from '../NotificationsContext'
|
||||||
|
|
||||||
const HIGH_BALANCE_KEY = 'cryptoHighBalance'
|
const HIGH_BALANCE_KEY = 'highBalance'
|
||||||
const LOW_BALANCE_KEY = 'cryptoLowBalance'
|
const LOW_BALANCE_KEY = 'lowBalance'
|
||||||
const CRYPTOCURRENCY_KEY = 'cryptoCurrency'
|
const CRYPTOCURRENCY_KEY = 'cryptoCurrency'
|
||||||
const NAME = 'cryptoBalanceOverrides'
|
const NAME = 'cryptoBalanceOverrides'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { offColor } from 'src/styling/variables'
|
||||||
|
|
||||||
const { p } = typographyStyles
|
const { p } = typographyStyles
|
||||||
|
|
||||||
const styles = {
|
export default {
|
||||||
wrapper: {
|
wrapper: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
|
@ -81,5 +81,3 @@ const styles = {
|
||||||
width: 215
|
width: 215
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default styles
|
|
||||||
|
|
|
||||||
833
package-lock.json
generated
833
package-lock.json
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue