Feat: make dashboard and machine profile page
This commit is contained in:
parent
1df90c3196
commit
c21cdb13e1
29 changed files with 717 additions and 135 deletions
|
|
@ -240,6 +240,10 @@ const typeDefs = gql`
|
||||||
created: Date
|
created: Date
|
||||||
age: Float
|
age: Float
|
||||||
deviceTime: Date
|
deviceTime: Date
|
||||||
|
type Rate {
|
||||||
|
code: String
|
||||||
|
name: String
|
||||||
|
rate: Float
|
||||||
}
|
}
|
||||||
|
|
||||||
type Rate {
|
type Rate {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ function batch (from = new Date(0).toISOString(), until = new Date().toISOString
|
||||||
c.front_camera_path as customer_front_camera_path,
|
c.front_camera_path as customer_front_camera_path,
|
||||||
c.id_card_photo_path as customer_id_card_photo_path,
|
c.id_card_photo_path as customer_id_card_photo_path,
|
||||||
((not txs.send_confirmed) and (txs.created <= now() - interval $1)) as expired
|
((not txs.send_confirmed) and (txs.created <= now() - interval $1)) as expired
|
||||||
from cash_in_txs as txs
|
from cash_in_txs as txs
|
||||||
left outer join customers c on txs.customer_id = c.id
|
left outer join customers c on txs.customer_id = c.id
|
||||||
where txs.created >= $2 and txs.created <= $3 ${
|
where txs.created >= $2 and txs.created <= $3 ${
|
||||||
id !== null ? `and txs.device_id = $6` : ``
|
id !== null ? `and txs.device_id = $6` : ``
|
||||||
|
|
@ -54,7 +54,7 @@ function batch (from = new Date(0).toISOString(), until = new Date().toISOString
|
||||||
c.front_camera_path as customer_front_camera_path,
|
c.front_camera_path as customer_front_camera_path,
|
||||||
c.id_card_photo_path as customer_id_card_photo_path,
|
c.id_card_photo_path as customer_id_card_photo_path,
|
||||||
(extract(epoch from (now() - greatest(txs.created, txs.confirmed_at))) * 1000) >= $1 as expired
|
(extract(epoch from (now() - greatest(txs.created, txs.confirmed_at))) * 1000) >= $1 as expired
|
||||||
from cash_out_txs txs
|
from cash_out_txs txs
|
||||||
inner join cash_out_actions actions on txs.id = actions.tx_id
|
inner join cash_out_actions actions on txs.id = actions.tx_id
|
||||||
and actions.action = 'provisionAddress'
|
and actions.action = 'provisionAddress'
|
||||||
left outer join customers c on txs.customer_id = c.id
|
left outer join customers c on txs.customer_id = c.id
|
||||||
|
|
|
||||||
|
|
@ -147,21 +147,6 @@ function plugins (settings, deviceId) {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
function getLcmOrBigx2 (n1, n2) {
|
|
||||||
let big = Math.max(n1, n2)
|
|
||||||
let small = Math.min(n1, n2)
|
|
||||||
|
|
||||||
let i = big * 2
|
|
||||||
while (i % small !== 0) {
|
|
||||||
i += lar
|
|
||||||
}
|
|
||||||
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor
|
|
||||||
function buildAvailableCassettes (excludeTxId) {
|
function buildAvailableCassettes (excludeTxId) {
|
||||||
const cashOutConfig = configManager.getCashOut(deviceId, settings.config)
|
const cashOutConfig = configManager.getCashOut(deviceId, settings.config)
|
||||||
|
|
||||||
|
|
@ -169,7 +154,6 @@ function plugins (settings, deviceId) {
|
||||||
|
|
||||||
const denominations = [cashOutConfig.top, cashOutConfig.bottom]
|
const denominations = [cashOutConfig.top, cashOutConfig.bottom]
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
const virtualCassettes = [Math.max(cashOutConfig.top, cashOutConfig.bottom) * 2]
|
const virtualCassettes = [Math.max(cashOutConfig.top, cashOutConfig.bottom) * 2]
|
||||||
|
|
||||||
return Promise.all([dbm.cassetteCounts(deviceId), cashOutHelper.redeemableTxs(deviceId, excludeTxId)])
|
return Promise.all([dbm.cassetteCounts(deviceId), cashOutHelper.redeemableTxs(deviceId, excludeTxId)])
|
||||||
|
|
@ -179,11 +163,6 @@ function plugins (settings, deviceId) {
|
||||||
const counts = argv.cassettes
|
const counts = argv.cassettes
|
||||||
? argv.cassettes.split(',')
|
? argv.cassettes.split(',')
|
||||||
: rec.counts
|
: rec.counts
|
||||||
=======
|
|
||||||
const virtualCassettes = [
|
|
||||||
getLcmOrBigx2(cashOutConfig.top, cashOutConfig.bottom)
|
|
||||||
]
|
|
||||||
>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor
|
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
dbm.cassetteCounts(deviceId),
|
dbm.cassetteCounts(deviceId),
|
||||||
|
|
@ -288,7 +267,6 @@ function plugins (settings, deviceId) {
|
||||||
currentConfigVersionPromise
|
currentConfigVersionPromise
|
||||||
].concat(tickerPromises, balancePromises, testnetPromises, currentAvailablePromoCodes)
|
].concat(tickerPromises, balancePromises, testnetPromises, currentAvailablePromoCodes)
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
.then(arr => {
|
.then(arr => {
|
||||||
const cassettes = arr[0]
|
const cassettes = arr[0]
|
||||||
|
|
@ -310,26 +288,6 @@ function plugins (settings, deviceId) {
|
||||||
areThereAvailablePromoCodes
|
areThereAvailablePromoCodes
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
=======
|
|
||||||
return Promise.all(promises).then(arr => {
|
|
||||||
const cassettes = arr[0]
|
|
||||||
const configVersion = arr[2]
|
|
||||||
const cryptoCodesCount = cryptoCodes.length
|
|
||||||
const tickers = arr.slice(3, cryptoCodesCount + 3)
|
|
||||||
const balances = arr.slice(cryptoCodesCount + 3, 2 * cryptoCodesCount + 3)
|
|
||||||
const testNets = arr.slice(2 * cryptoCodesCount + 3)
|
|
||||||
const coinParams = _.zip(cryptoCodes, testNets)
|
|
||||||
const coinsWithoutRate = _.map(mapCoinSettings, coinParams)
|
|
||||||
|
|
||||||
return {
|
|
||||||
cassettes,
|
|
||||||
rates: buildRates(tickers),
|
|
||||||
balances: buildBalances(balances),
|
|
||||||
coins: _.zipWith(_.assign, coinsWithoutRate, tickers),
|
|
||||||
configVersion
|
|
||||||
}
|
|
||||||
})
|
|
||||||
>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendCoins (tx) {
|
function sendCoins (tx) {
|
||||||
|
|
@ -648,15 +606,8 @@ function plugins (settings, deviceId) {
|
||||||
const notifications = configManager.getGlobalNotifications(settings.config)
|
const notifications = configManager.getGlobalNotifications(settings.config)
|
||||||
|
|
||||||
let promises = []
|
let promises = []
|
||||||
<<<<<<< HEAD
|
|
||||||
if (notifications.email.active && rec.email) promises.push(email.sendMessage(settings, rec))
|
if (notifications.email.active && rec.email) promises.push(email.sendMessage(settings, rec))
|
||||||
if (notifications.sms.active && rec.sms) promises.push(sms.sendMessage(settings, rec))
|
if (notifications.sms.active && rec.sms) promises.push(sms.sendMessage(settings, rec))
|
||||||
=======
|
|
||||||
if (notifications.email.active && rec.email)
|
|
||||||
promises.push(email.sendMessage(settings, rec))
|
|
||||||
if (notifications.sms.active && rec.sms)
|
|
||||||
promises.push(sms.sendMessage(settings, rec))
|
|
||||||
>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor
|
|
||||||
|
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
}
|
}
|
||||||
|
|
@ -757,25 +708,11 @@ function plugins (settings, deviceId) {
|
||||||
fiatCode
|
fiatCode
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
if (_.isFinite(lowAlertThreshold) && BN(fiatBalance.balance).lt(lowAlertThreshold)) {
|
if (_.isFinite(lowAlertThreshold) && BN(fiatBalance.balance).lt(lowAlertThreshold)) {
|
||||||
=======
|
|
||||||
if (
|
|
||||||
_.isFinite(lowAlertThreshold) &&
|
|
||||||
BN(fiatBalance.balance).lt(lowAlertThreshold)
|
|
||||||
)
|
|
||||||
>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor
|
|
||||||
return _.set('code')('LOW_CRYPTO_BALANCE')(req)
|
return _.set('code')('LOW_CRYPTO_BALANCE')(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
if (_.isFinite(highAlertThreshold) && BN(fiatBalance.balance).gt(highAlertThreshold)) {
|
if (_.isFinite(highAlertThreshold) && BN(fiatBalance.balance).gt(highAlertThreshold)) {
|
||||||
=======
|
|
||||||
if (
|
|
||||||
_.isFinite(highAlertThreshold) &&
|
|
||||||
BN(fiatBalance.balance).gt(highAlertThreshold)
|
|
||||||
)
|
|
||||||
>>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor
|
|
||||||
return _.set('code')('HIGH_CRYPTO_BALANCE')(req)
|
return _.set('code')('HIGH_CRYPTO_BALANCE')(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ 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 = {}
|
||||||
|
|
||||||
|
|
@ -39,4 +40,26 @@ const getRates = mem(_getRates, {
|
||||||
cacheKey: (settings, fiatCode, cryptoCode) => JSON.stringify([fiatCode, cryptoCode])
|
cacheKey: (settings, fiatCode, cryptoCode) => JSON.stringify([fiatCode, cryptoCode])
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = { getRates }
|
const getBtcRates = (to = null, from = 'USD') => {
|
||||||
|
// 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 }
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,7 @@ 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 }) => {
|
||||||
|
|
@ -124,5 +125,6 @@ export {
|
||||||
Mono,
|
Mono,
|
||||||
Label1,
|
Label1,
|
||||||
Label2,
|
Label2,
|
||||||
Label3
|
Label3,
|
||||||
|
Label4
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,76 +1,130 @@
|
||||||
|
import { useQuery } from '@apollo/react-hooks'
|
||||||
import Button from '@material-ui/core/Button'
|
import Button from '@material-ui/core/Button'
|
||||||
import Grid from '@material-ui/core/Grid'
|
import Grid from '@material-ui/core/Grid'
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import React from 'react'
|
import gql from 'graphql-tag'
|
||||||
|
import * as R from 'ramda'
|
||||||
import { cardState as cardState_ } from 'src/components/CollapsibleCard'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { Label1, H4 } from 'src/components/typography'
|
import { Label1, H4 } from 'src/components/typography'
|
||||||
|
|
||||||
import styles from './Alerts.styles'
|
import styles from '../Dashboard.styles'
|
||||||
|
|
||||||
import AlertsTable from './AlertsTable'
|
import AlertsTable from './AlertsTable'
|
||||||
|
|
||||||
const NUM_TO_RENDER = 3
|
const NUM_TO_RENDER = 3
|
||||||
|
|
||||||
const data = {
|
const GET_ALERTS = gql`
|
||||||
alerts: [
|
query getAlerts {
|
||||||
{ text: 'alert 1' },
|
alerts {
|
||||||
{ text: 'alert 2' },
|
id
|
||||||
{ text: 'alert 3' },
|
type
|
||||||
{ text: 'alert 4' },
|
detail
|
||||||
{ text: 'alert 5' }
|
message
|
||||||
]
|
created
|
||||||
}
|
read
|
||||||
|
valid
|
||||||
|
}
|
||||||
|
machines {
|
||||||
|
deviceId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
const Alerts = ({ onReset, onExpand, size }) => {
|
const Alerts = ({ cardState, setRightSideState }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
const [showAllItems, setShowAllItems] = useState(false)
|
||||||
|
const { data } = useQuery(GET_ALERTS)
|
||||||
|
|
||||||
const showAllItems = size === cardState_.EXPANDED
|
const alerts = R.path(['alerts'])(data) ?? []
|
||||||
|
const machines = R.compose(
|
||||||
|
R.map(R.prop('name')),
|
||||||
|
R.indexBy(R.prop('deviceId'))
|
||||||
|
)(data?.machines ?? [])
|
||||||
|
|
||||||
const alertsLength = () => (data ? data.alerts.length : 0)
|
const showExpandButton = alerts.length > NUM_TO_RENDER && !showAllItems
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (cardState.cardSize === 'small' || cardState.cardSize === 'default') {
|
||||||
|
setShowAllItems(false)
|
||||||
|
}
|
||||||
|
}, [cardState.cardSize])
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
setRightSideState({
|
||||||
|
systemStatus: { cardSize: 'default', buttonName: 'Show less' },
|
||||||
|
alerts: { cardSize: 'default', buttonName: 'Show less' }
|
||||||
|
})
|
||||||
|
setShowAllItems(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const showAllClick = () => {
|
||||||
|
setShowAllItems(true)
|
||||||
|
setRightSideState({
|
||||||
|
systemStatus: { cardSize: 'small', buttonName: 'Show machines' },
|
||||||
|
alerts: { cardSize: 'big', buttonName: 'Show less' }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={classes.container}>
|
<div
|
||||||
<H4 className={classes.h4}>{`Alerts (${alertsLength()})`}</H4>
|
style={{
|
||||||
{showAllItems && (
|
display: 'flex',
|
||||||
<Label1 className={classes.upperButtonLabel}>
|
justifyContent: 'space-between'
|
||||||
<Button
|
}}>
|
||||||
onClick={onReset}
|
<H4 className={classes.h4}>{`Alerts ${
|
||||||
size="small"
|
data ? `(${alerts.length})` : 0
|
||||||
disableRipple
|
}`}</H4>
|
||||||
disableFocusRipple
|
{(showAllItems || cardState.cardSize === 'small') && (
|
||||||
className={classes.button}>
|
<>
|
||||||
{'Show less'}
|
<Label1
|
||||||
</Button>
|
style={{
|
||||||
</Label1>
|
textAlign: 'center',
|
||||||
|
marginBottom: 0,
|
||||||
|
marginTop: 0
|
||||||
|
}}>
|
||||||
|
<Button
|
||||||
|
onClick={reset}
|
||||||
|
size="small"
|
||||||
|
disableRipple
|
||||||
|
disableFocusRipple
|
||||||
|
className={classes.button}>
|
||||||
|
{cardState.buttonName}
|
||||||
|
</Button>
|
||||||
|
</Label1>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<>
|
{cardState.cardSize !== 'small' && (
|
||||||
<Grid container spacing={1}>
|
<>
|
||||||
<Grid item xs={12}>
|
<Grid container spacing={1}>
|
||||||
<AlertsTable
|
<Grid item xs={12}>
|
||||||
numToRender={showAllItems ? data?.alerts.length : NUM_TO_RENDER}
|
<AlertsTable
|
||||||
alerts={data?.alerts ?? []}
|
numToRender={showAllItems ? alerts.length : NUM_TO_RENDER}
|
||||||
/>
|
alerts={alerts}
|
||||||
{!showAllItems && (
|
machines={machines}
|
||||||
<>
|
/>
|
||||||
<Label1 className={classes.centerLabel}>
|
{showExpandButton && (
|
||||||
<Button
|
<>
|
||||||
onClick={() => onExpand('alerts')}
|
<Label1 style={{ textAlign: 'center', marginBottom: 0 }}>
|
||||||
size="small"
|
<Button
|
||||||
disableRipple
|
onClick={showAllClick}
|
||||||
disableFocusRipple
|
size="small"
|
||||||
className={classes.button}>
|
disableRipple
|
||||||
{`Show all (${data.alerts.length})`}
|
disableFocusRipple
|
||||||
</Button>
|
className={classes.button}>
|
||||||
</Label1>
|
{`Show all (${alerts.length})`}
|
||||||
</>
|
</Button>
|
||||||
)}
|
</Label1>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</>
|
||||||
</>
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import Grid from '@material-ui/core/Grid'
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import TitleSection from 'src/components/layout/TitleSection'
|
import TitleSection from 'src/components/layout/TitleSection'
|
||||||
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'
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import classnames from 'classnames'
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
import { Label2 } from 'src/components/typography'
|
import { Label2 } from 'src/components/typography'
|
||||||
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'
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import Button from '@material-ui/core/Button'
|
||||||
import Grid from '@material-ui/core/Grid'
|
import Grid from '@material-ui/core/Grid'
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
import CollapsibleCard, { cardState } from 'src/components/CollapsibleCard'
|
import CollapsibleCard, { cardState } from 'src/components/CollapsibleCard'
|
||||||
import { H4, Label1 } from 'src/components/typography'
|
import { H4, Label1 } from 'src/components/typography'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import * as d3 from 'd3'
|
import * as d3 from 'd3'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { useEffect, useRef, useCallback } from 'react'
|
import React, { useEffect, useRef, useCallback } from 'react'
|
||||||
|
|
||||||
import { backgroundColor, zircon, primaryColor } from 'src/styling/variables'
|
import { backgroundColor, zircon, primaryColor } from 'src/styling/variables'
|
||||||
|
|
||||||
const transactionProfit = tx => {
|
const transactionProfit = tx => {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import * as d3 from 'd3'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { useEffect, useRef, useCallback } from 'react'
|
import React, { useEffect, useRef, useCallback } from 'react'
|
||||||
|
|
||||||
import { backgroundColor, java, neon } from 'src/styling/variables'
|
import { backgroundColor, java, neon } from 'src/styling/variables'
|
||||||
|
|
||||||
const RefScatterplot = ({ data: realData, timeFrame }) => {
|
const RefScatterplot = ({ data: realData, timeFrame }) => {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*eslint-disable*/
|
||||||
|
import { scaleLinear, scaleTime, max, axisLeft, axisBottom, select } from 'd3'
|
||||||
|
import React, { useMemo } from 'react'
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
|
const data = [
|
||||||
|
[0, '2020-11-08T18:00:05.664Z'],
|
||||||
|
[40.01301, '2020-11-09T11:17:05.664Z']
|
||||||
|
]
|
||||||
|
|
||||||
|
const marginTop = 10
|
||||||
|
const marginRight = 30
|
||||||
|
const marginBottom = 30
|
||||||
|
const marginLeft = 60
|
||||||
|
const width = 510 - marginLeft - marginRight
|
||||||
|
const height = 141 - marginTop - marginBottom
|
||||||
|
|
||||||
|
const Scatterplot = ({ data: realData }) => {
|
||||||
|
const x = scaleTime()
|
||||||
|
.domain([
|
||||||
|
moment()
|
||||||
|
.add(-1, 'day')
|
||||||
|
.valueOf(),
|
||||||
|
moment().valueOf()
|
||||||
|
])
|
||||||
|
.range([0, width])
|
||||||
|
.nice()
|
||||||
|
|
||||||
|
const y = scaleLinear()
|
||||||
|
.domain([0, 1000])
|
||||||
|
.range([height, 0])
|
||||||
|
.nice()
|
||||||
|
|
||||||
|
// viewBox="0 0 540 141"
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<svg
|
||||||
|
width={width + marginLeft + marginRight}
|
||||||
|
height={height + marginTop + marginBottom}>
|
||||||
|
<g transform={`translate(${marginLeft},${marginTop})`}>
|
||||||
|
<XAxis
|
||||||
|
transform={`translate(0, ${height + marginTop})`}
|
||||||
|
scale={x}
|
||||||
|
numTicks={6}
|
||||||
|
/>
|
||||||
|
<g>{axisLeft(y)}</g>
|
||||||
|
{/* <YAxis transform={`translate(0, 0)`} scale={y} numTicks={6} /> */}
|
||||||
|
<RenderCircles data={data} scale={{ x, y }} />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const XAxis = ({
|
||||||
|
range = [10, 500],
|
||||||
|
transform,
|
||||||
|
scale: xScale,
|
||||||
|
numTicks = 7
|
||||||
|
}) => {
|
||||||
|
const ticks = useMemo(() => {
|
||||||
|
return xScale.ticks(numTicks).map(value => ({
|
||||||
|
value,
|
||||||
|
xOffset: xScale(value)
|
||||||
|
}))
|
||||||
|
}, [range.join('-')])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<g transform={transform}>
|
||||||
|
{ticks.map(({ value, xOffset }) => (
|
||||||
|
<g key={value} transform={`translate(${xOffset}, 0)`}>
|
||||||
|
<text
|
||||||
|
key={value}
|
||||||
|
style={{
|
||||||
|
fontSize: '10px',
|
||||||
|
textAnchor: 'middle',
|
||||||
|
transform: 'translateY(10px)'
|
||||||
|
}}>
|
||||||
|
{value.getHours()}
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
))}
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const YAxis = ({
|
||||||
|
range = [10, 500],
|
||||||
|
transform,
|
||||||
|
scale: xScale,
|
||||||
|
numTicks = 7
|
||||||
|
}) => {
|
||||||
|
const ticks = useMemo(() => {
|
||||||
|
return xScale.ticks(numTicks).map(value => ({
|
||||||
|
value,
|
||||||
|
xOffset: xScale(value)
|
||||||
|
}))
|
||||||
|
}, [range.join('-')])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<g transform={transform}>
|
||||||
|
{ticks.map(({ value, xOffset }) => (
|
||||||
|
<g key={value} transform={`translate(0, ${xOffset})`}>
|
||||||
|
<text
|
||||||
|
key={value}
|
||||||
|
style={{
|
||||||
|
fontSize: '10px',
|
||||||
|
textAnchor: 'middle',
|
||||||
|
transform: 'translateX(-10px)'
|
||||||
|
}}>
|
||||||
|
{value}
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
))}
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const RenderCircles = ({ data, scale }) => {
|
||||||
|
let renderCircles = data.map((item, idx) => {
|
||||||
|
return (
|
||||||
|
<circle
|
||||||
|
cx={scale.x(new Date(item[1]))}
|
||||||
|
cy={scale.y(item[0])}
|
||||||
|
r="4"
|
||||||
|
style={{ fill: 'rgba(25, 158, 199, .9)' }}
|
||||||
|
key={idx}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return <g>{renderCircles}</g>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Scatterplot
|
||||||
|
|
@ -2,7 +2,6 @@ import { makeStyles } from '@material-ui/core/styles'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
import { H4 } from 'src/components/typography'
|
import { H4 } from 'src/components/typography'
|
||||||
|
|
||||||
import styles from './SystemPerformance.styles'
|
import styles from './SystemPerformance.styles'
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import gql from 'graphql-tag'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
import { Label2 } from 'src/components/typography/index'
|
import { Label2 } from 'src/components/typography/index'
|
||||||
import { ReactComponent as TriangleDown } from 'src/styling/icons/arrow/triangle_down.svg'
|
import { ReactComponent as TriangleDown } from 'src/styling/icons/arrow/triangle_down.svg'
|
||||||
import { ReactComponent as TriangleUp } from 'src/styling/icons/arrow/triangle_up.svg'
|
import { ReactComponent as TriangleUp } from 'src/styling/icons/arrow/triangle_up.svg'
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import TableRow from '@material-ui/core/TableRow'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useHistory } from 'react-router-dom'
|
import { useHistory } from 'react-router-dom'
|
||||||
|
|
||||||
import { Status } from 'src/components/Status'
|
import { Status } from 'src/components/Status'
|
||||||
import { Label2, TL2 } from 'src/components/typography'
|
import { Label2, TL2 } from 'src/components/typography'
|
||||||
// import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
|
// import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import Grid from '@material-ui/core/Grid'
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { cardState as cardState_ } from 'src/components/CollapsibleCard'
|
import { cardState as cardState_ } from 'src/components/CollapsibleCard'
|
||||||
// import ActionButton from 'src/components/buttons/ActionButton'
|
// import ActionButton from 'src/components/buttons/ActionButton'
|
||||||
import { H4, TL2, Label1 } from 'src/components/typography'
|
import { H4, TL2, Label1 } from 'src/components/typography'
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,11 @@ import { useMutation } from '@apollo/react-hooks'
|
||||||
import { makeStyles } from '@material-ui/core'
|
import { makeStyles } from '@material-ui/core'
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import * as Yup from 'yup'
|
|
||||||
|
|
||||||
import { Table as EditableTable } from 'src/components/editableTable'
|
import { Table as EditableTable } from 'src/components/editableTable'
|
||||||
import { CashOut } from 'src/components/inputs/cashbox/Cashbox'
|
import { CashOut } from 'src/components/inputs/cashbox/Cashbox'
|
||||||
import { NumberInput } from 'src/components/inputs/formik'
|
import { NumberInput } from 'src/components/inputs/formik'
|
||||||
import { fromNamespace } from 'src/utils/config'
|
import { fromNamespace } from 'src/utils/config'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
import styles from './Cassettes.styles'
|
import styles from './Cassettes.styles'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import { useQuery, useMutation } from '@apollo/react-hooks'
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { Table as EditableTable } from 'src/components/editableTable'
|
import { Table as EditableTable } from 'src/components/editableTable'
|
||||||
import { fromNamespace, toNamespace, namespaces } from 'src/utils/config'
|
import { fromNamespace, toNamespace, namespaces } from 'src/utils/config'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { Label3, P } from 'src/components/typography'
|
import { Label3, P } from 'src/components/typography'
|
||||||
|
|
||||||
import styles from '../Machines.styles'
|
import styles from '../Machines.styles'
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
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
|
||||||
|
|
@ -8,7 +8,6 @@ import {
|
||||||
CellMeasurer,
|
CellMeasurer,
|
||||||
CellMeasurerCache
|
CellMeasurerCache
|
||||||
} from 'react-virtualized'
|
} from 'react-virtualized'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TBody,
|
TBody,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { zircon } from 'src/styling/variables'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
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'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,195 @@
|
||||||
|
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)
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
import typographyStyles from 'src/components/typography/styles'
|
||||||
|
import { offColor } from 'src/styling/variables'
|
||||||
|
|
||||||
|
const { p } = typographyStyles
|
||||||
|
|
||||||
|
export default {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
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
|
||||||
|
|
@ -5,7 +5,6 @@ import gql from 'graphql-tag'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import DetailsRow from 'src/pages/Transactions/DetailsCard'
|
import DetailsRow from 'src/pages/Transactions/DetailsCard'
|
||||||
import { mainStyles } from 'src/pages/Transactions/Transactions.styles'
|
import { mainStyles } from 'src/pages/Transactions/Transactions.styles'
|
||||||
import { getStatus } from 'src/pages/Transactions/helper'
|
import { getStatus } from 'src/pages/Transactions/helper'
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
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 }
|
||||||
|
|
@ -8,7 +8,6 @@ import gql from 'graphql-tag'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { Link, useLocation } from 'react-router-dom'
|
import { Link, useLocation } from 'react-router-dom'
|
||||||
|
|
||||||
import { TL1, TL2, Label3 } from 'src/components/typography'
|
import { TL1, TL2, Label3 } from 'src/components/typography'
|
||||||
|
|
||||||
import Cassettes from './MachineComponents/Cassettes'
|
import Cassettes from './MachineComponents/Cassettes'
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,18 @@ const useStyles = makeStyles({
|
||||||
})
|
})
|
||||||
|
|
||||||
const tree = [
|
const tree = [
|
||||||
|
{
|
||||||
|
key: 'dashboard',
|
||||||
|
label: 'Dashboard',
|
||||||
|
route: '/dashboard',
|
||||||
|
component: Dashboard
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'machines',
|
||||||
|
label: 'Machines',
|
||||||
|
route: '/machines',
|
||||||
|
component: Machines
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'transactions',
|
key: 'transactions',
|
||||||
label: 'Transactions',
|
label: 'Transactions',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue