From c21cdb13e10d9f7e364a6085a1d91ba228a7966a Mon Sep 17 00:00:00 2001
From: Cesar <26280794+csrapr@users.noreply.github.com>
Date: Tue, 17 Nov 2020 12:13:10 +0000
Subject: [PATCH] Feat: make dashboard and machine profile page
---
lib/new-admin/graphql/schema.js | 4 +
lib/new-admin/transactions.js | 4 +-
lib/plugins.js | 63 ------
lib/ticker.js | 25 ++-
.../src/components/typography/index.js | 4 +-
.../src/pages/Dashboard/Alerts/Alerts.js | 158 +++++++++-----
.../src/pages/Dashboard/Dashboard.js | 1 -
.../src/pages/Dashboard/Footer/Footer.js | 1 -
.../src/pages/Dashboard/RightSide.js | 1 -
.../SystemPerformance/Graphs/RefLineChart.js | 1 -
.../Graphs/RefScatterplot.js | 1 -
.../SystemPerformance/Graphs/Scatterplot.js | 134 ++++++++++++
.../pages/Dashboard/SystemPerformance/Nav.js | 1 -
.../SystemPerformance/SystemPerformance.js | 1 -
.../Dashboard/SystemStatus/MachinesTable.js | 1 -
.../Dashboard/SystemStatus/SystemStatus.js | 1 -
.../MachineComponents/Cassettes/Cassettes.js | 3 +-
.../Commissions/Commissions.js | 1 -
.../Machines/MachineComponents/Details.js | 1 -
.../Transactions/CopyToClipboard.js | 74 +++++++
.../Transactions/DataTable.js | 1 -
.../Transactions/DataTable.styles.js | 43 ++++
.../Transactions/DetailsCard.js | 195 ++++++++++++++++++
.../Transactions/DetailsCard.styles.js | 84 ++++++++
.../MachineComponents/Transactions/Stripes.js | 12 ++
.../Transactions/Transactions.js | 1 -
.../MachineComponents/Transactions/helper.js | 23 +++
.../src/pages/Machines/Machines.js | 1 -
new-lamassu-admin/src/routing/routes.js | 12 ++
29 files changed, 717 insertions(+), 135 deletions(-)
create mode 100644 new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/Scatterplot.js
create mode 100644 new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/CopyToClipboard.js
create mode 100644 new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DataTable.styles.js
create mode 100644 new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DetailsCard.js
create mode 100644 new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DetailsCard.styles.js
create mode 100644 new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Stripes.js
create mode 100644 new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/helper.js
diff --git a/lib/new-admin/graphql/schema.js b/lib/new-admin/graphql/schema.js
index c363faff..92e514a6 100644
--- a/lib/new-admin/graphql/schema.js
+++ b/lib/new-admin/graphql/schema.js
@@ -240,6 +240,10 @@ const typeDefs = gql`
created: Date
age: Float
deviceTime: Date
+ type Rate {
+ code: String
+ name: String
+ rate: Float
}
type Rate {
diff --git a/lib/new-admin/transactions.js b/lib/new-admin/transactions.js
index c7208961..ba3156d2 100644
--- a/lib/new-admin/transactions.js
+++ b/lib/new-admin/transactions.js
@@ -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.id_card_photo_path as customer_id_card_photo_path,
((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
where txs.created >= $2 and txs.created <= $3 ${
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.id_card_photo_path as customer_id_card_photo_path,
(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
and actions.action = 'provisionAddress'
left outer join customers c on txs.customer_id = c.id
diff --git a/lib/plugins.js b/lib/plugins.js
index 3e13f650..8da6fa99 100644
--- a/lib/plugins.js
+++ b/lib/plugins.js
@@ -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) {
const cashOutConfig = configManager.getCashOut(deviceId, settings.config)
@@ -169,7 +154,6 @@ function plugins (settings, deviceId) {
const denominations = [cashOutConfig.top, cashOutConfig.bottom]
-<<<<<<< HEAD
const virtualCassettes = [Math.max(cashOutConfig.top, cashOutConfig.bottom) * 2]
return Promise.all([dbm.cassetteCounts(deviceId), cashOutHelper.redeemableTxs(deviceId, excludeTxId)])
@@ -179,11 +163,6 @@ function plugins (settings, deviceId) {
const counts = argv.cassettes
? argv.cassettes.split(',')
: rec.counts
-=======
- const virtualCassettes = [
- getLcmOrBigx2(cashOutConfig.top, cashOutConfig.bottom)
- ]
->>>>>>> 1706b2c... Feat: save highVolumeTxs on DB and plugins code refactor
return Promise.all([
dbm.cassetteCounts(deviceId),
@@ -288,7 +267,6 @@ function plugins (settings, deviceId) {
currentConfigVersionPromise
].concat(tickerPromises, balancePromises, testnetPromises, currentAvailablePromoCodes)
-<<<<<<< HEAD
return Promise.all(promises)
.then(arr => {
const cassettes = arr[0]
@@ -310,26 +288,6 @@ function plugins (settings, deviceId) {
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) {
@@ -648,15 +606,8 @@ function plugins (settings, deviceId) {
const notifications = configManager.getGlobalNotifications(settings.config)
let promises = []
-<<<<<<< HEAD
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.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)
}
@@ -757,25 +708,11 @@ function plugins (settings, deviceId) {
fiatCode
}
-<<<<<<< HEAD
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)
}
-<<<<<<< HEAD
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)
}
diff --git a/lib/ticker.js b/lib/ticker.js
index 85fc3266..ef710443 100644
--- a/lib/ticker.js
+++ b/lib/ticker.js
@@ -2,6 +2,7 @@ const mem = require('mem')
const configManager = require('./new-config-manager')
const ph = require('./plugin-helper')
const logger = require('./logger')
+const axios = require('axios')
const lastRate = {}
@@ -39,4 +40,26 @@ const getRates = mem(_getRates, {
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 }
diff --git a/new-lamassu-admin/src/components/typography/index.js b/new-lamassu-admin/src/components/typography/index.js
index 2cd0a09e..a9681372 100644
--- a/new-lamassu-admin/src/components/typography/index.js
+++ b/new-lamassu-admin/src/components/typography/index.js
@@ -91,6 +91,7 @@ const TL2 = pBuilder('tl2')
const Label1 = pBuilder('label1')
const Label2 = pBuilder('label2')
const Label3 = pBuilder('label3')
+const Label4 = pBuilder('regularLabel')
function pBuilder(elementClass) {
return ({ inline, noMargin, className, children, ...props }) => {
@@ -124,5 +125,6 @@ export {
Mono,
Label1,
Label2,
- Label3
+ Label3,
+ Label4
}
diff --git a/new-lamassu-admin/src/pages/Dashboard/Alerts/Alerts.js b/new-lamassu-admin/src/pages/Dashboard/Alerts/Alerts.js
index 6ee74b27..d0ad8adb 100644
--- a/new-lamassu-admin/src/pages/Dashboard/Alerts/Alerts.js
+++ b/new-lamassu-admin/src/pages/Dashboard/Alerts/Alerts.js
@@ -1,76 +1,130 @@
+import { useQuery } from '@apollo/react-hooks'
import Button from '@material-ui/core/Button'
import Grid from '@material-ui/core/Grid'
import { makeStyles } from '@material-ui/core/styles'
-import React from 'react'
-
-import { cardState as cardState_ } from 'src/components/CollapsibleCard'
+import gql from 'graphql-tag'
+import * as R from 'ramda'
+import React, { useState, useEffect } from 'react'
import { Label1, H4 } from 'src/components/typography'
-import styles from './Alerts.styles'
+import styles from '../Dashboard.styles'
+
import AlertsTable from './AlertsTable'
const NUM_TO_RENDER = 3
-const data = {
- alerts: [
- { text: 'alert 1' },
- { text: 'alert 2' },
- { text: 'alert 3' },
- { text: 'alert 4' },
- { text: 'alert 5' }
- ]
-}
+const GET_ALERTS = gql`
+ query getAlerts {
+ alerts {
+ id
+ type
+ detail
+ message
+ created
+ read
+ valid
+ }
+ machines {
+ deviceId
+ name
+ }
+ }
+`
const useStyles = makeStyles(styles)
-const Alerts = ({ onReset, onExpand, size }) => {
+const Alerts = ({ cardState, setRightSideState }) => {
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 (
<>
-
-
{`Alerts (${alertsLength()})`}
- {showAllItems && (
-
-
-
+
+
{`Alerts ${
+ data ? `(${alerts.length})` : 0
+ }`}
+ {(showAllItems || cardState.cardSize === 'small') && (
+ <>
+
+
+
+ >
)}
- <>
-
-
-
- {!showAllItems && (
- <>
-
-
-
- >
- )}
+ {cardState.cardSize !== 'small' && (
+ <>
+
+
+
+ {showExpandButton && (
+ <>
+
+
+
+ >
+ )}
+
-
- >
+ >
+ )}
>
)
}
diff --git a/new-lamassu-admin/src/pages/Dashboard/Dashboard.js b/new-lamassu-admin/src/pages/Dashboard/Dashboard.js
index dd875662..c345be9c 100644
--- a/new-lamassu-admin/src/pages/Dashboard/Dashboard.js
+++ b/new-lamassu-admin/src/pages/Dashboard/Dashboard.js
@@ -2,7 +2,6 @@ import Grid from '@material-ui/core/Grid'
import { makeStyles } from '@material-ui/core/styles'
import classnames from 'classnames'
import React from 'react'
-
import TitleSection from 'src/components/layout/TitleSection'
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
diff --git a/new-lamassu-admin/src/pages/Dashboard/Footer/Footer.js b/new-lamassu-admin/src/pages/Dashboard/Footer/Footer.js
index 1f9b2034..dd9a8ffa 100644
--- a/new-lamassu-admin/src/pages/Dashboard/Footer/Footer.js
+++ b/new-lamassu-admin/src/pages/Dashboard/Footer/Footer.js
@@ -6,7 +6,6 @@ import classnames from 'classnames'
import gql from 'graphql-tag'
import * as R from 'ramda'
import React, { useState } from 'react'
-
import { Label2 } from 'src/components/typography'
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
diff --git a/new-lamassu-admin/src/pages/Dashboard/RightSide.js b/new-lamassu-admin/src/pages/Dashboard/RightSide.js
index 4a8ab0a4..6d2e5461 100644
--- a/new-lamassu-admin/src/pages/Dashboard/RightSide.js
+++ b/new-lamassu-admin/src/pages/Dashboard/RightSide.js
@@ -2,7 +2,6 @@ import Button from '@material-ui/core/Button'
import Grid from '@material-ui/core/Grid'
import { makeStyles } from '@material-ui/core/styles'
import React, { useState } from 'react'
-
import CollapsibleCard, { cardState } from 'src/components/CollapsibleCard'
import { H4, Label1 } from 'src/components/typography'
diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js
index 29d92d4f..c90f8048 100644
--- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js
+++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js
@@ -1,7 +1,6 @@
import * as d3 from 'd3'
import * as R from 'ramda'
import React, { useEffect, useRef, useCallback } from 'react'
-
import { backgroundColor, zircon, primaryColor } from 'src/styling/variables'
const transactionProfit = tx => {
diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js
index 4d7da250..a26da0a3 100644
--- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js
+++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js
@@ -2,7 +2,6 @@ import * as d3 from 'd3'
import moment from 'moment'
import * as R from 'ramda'
import React, { useEffect, useRef, useCallback } from 'react'
-
import { backgroundColor, java, neon } from 'src/styling/variables'
const RefScatterplot = ({ data: realData, timeFrame }) => {
diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/Scatterplot.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/Scatterplot.js
new file mode 100644
index 00000000..ef08a169
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/Scatterplot.js
@@ -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 (
+ <>
+
+ >
+ )
+}
+
+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 (
+
+ {ticks.map(({ value, xOffset }) => (
+
+
+ {value.getHours()}
+
+
+ ))}
+
+ )
+}
+
+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 (
+
+ {ticks.map(({ value, xOffset }) => (
+
+
+ {value}
+
+
+ ))}
+
+ )
+}
+
+const RenderCircles = ({ data, scale }) => {
+ let renderCircles = data.map((item, idx) => {
+ return (
+
+ )
+ })
+ return {renderCircles}
+}
+
+export default Scatterplot
diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Nav.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Nav.js
index 04c9bd7a..c0de11d5 100644
--- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Nav.js
+++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Nav.js
@@ -2,7 +2,6 @@ import { makeStyles } from '@material-ui/core/styles'
import classnames from 'classnames'
import * as R from 'ramda'
import React, { useState } from 'react'
-
import { H4 } from 'src/components/typography'
import styles from './SystemPerformance.styles'
diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js
index fd23dce7..bbfe8a3e 100644
--- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js
+++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js
@@ -6,7 +6,6 @@ import gql from 'graphql-tag'
import moment from 'moment'
import * as R from 'ramda'
import React, { useState } from 'react'
-
import { Label2 } from 'src/components/typography/index'
import { ReactComponent as TriangleDown } from 'src/styling/icons/arrow/triangle_down.svg'
import { ReactComponent as TriangleUp } from 'src/styling/icons/arrow/triangle_up.svg'
diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemStatus/MachinesTable.js b/new-lamassu-admin/src/pages/Dashboard/SystemStatus/MachinesTable.js
index df375db7..bbea843f 100644
--- a/new-lamassu-admin/src/pages/Dashboard/SystemStatus/MachinesTable.js
+++ b/new-lamassu-admin/src/pages/Dashboard/SystemStatus/MachinesTable.js
@@ -8,7 +8,6 @@ import TableRow from '@material-ui/core/TableRow'
import classnames from 'classnames'
import React from 'react'
import { useHistory } from 'react-router-dom'
-
import { Status } from 'src/components/Status'
import { Label2, TL2 } from 'src/components/typography'
// import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemStatus/SystemStatus.js b/new-lamassu-admin/src/pages/Dashboard/SystemStatus/SystemStatus.js
index 189c0902..aea73b0f 100644
--- a/new-lamassu-admin/src/pages/Dashboard/SystemStatus/SystemStatus.js
+++ b/new-lamassu-admin/src/pages/Dashboard/SystemStatus/SystemStatus.js
@@ -4,7 +4,6 @@ import Grid from '@material-ui/core/Grid'
import { makeStyles } from '@material-ui/core/styles'
import gql from 'graphql-tag'
import React from 'react'
-
import { cardState as cardState_ } from 'src/components/CollapsibleCard'
// import ActionButton from 'src/components/buttons/ActionButton'
import { H4, TL2, Label1 } from 'src/components/typography'
diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Cassettes/Cassettes.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Cassettes/Cassettes.js
index 9cf06374..0b82420b 100644
--- a/new-lamassu-admin/src/pages/Machines/MachineComponents/Cassettes/Cassettes.js
+++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Cassettes/Cassettes.js
@@ -2,12 +2,11 @@ import { useMutation } from '@apollo/react-hooks'
import { makeStyles } from '@material-ui/core'
import gql from 'graphql-tag'
import React from 'react'
-import * as Yup from 'yup'
-
import { Table as EditableTable } from 'src/components/editableTable'
import { CashOut } from 'src/components/inputs/cashbox/Cashbox'
import { NumberInput } from 'src/components/inputs/formik'
import { fromNamespace } from 'src/utils/config'
+import * as Yup from 'yup'
import styles from './Cassettes.styles'
diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/Commissions.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/Commissions.js
index 6b569961..f19d95d9 100644
--- a/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/Commissions.js
+++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/Commissions.js
@@ -2,7 +2,6 @@ import { useQuery, useMutation } from '@apollo/react-hooks'
import gql from 'graphql-tag'
import * as R from 'ramda'
import React from 'react'
-
import { Table as EditableTable } from 'src/components/editableTable'
import { fromNamespace, toNamespace, namespaces } from 'src/utils/config'
diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Details.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Details.js
index a47adfc7..2787eb28 100644
--- a/new-lamassu-admin/src/pages/Machines/MachineComponents/Details.js
+++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Details.js
@@ -1,7 +1,6 @@
import { makeStyles } from '@material-ui/core/styles'
import moment from 'moment'
import React from 'react'
-
import { Label3, P } from 'src/components/typography'
import styles from '../Machines.styles'
diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/CopyToClipboard.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/CopyToClipboard.js
new file mode 100644
index 00000000..ce6065c6
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/CopyToClipboard.js
@@ -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 (
+
+ {children && (
+ <>
+
+ {children}
+
+
+
+
+
+
+
+
+
+ >
+ )}
+
+ )
+}
+
+export default CopyToClipboard
diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DataTable.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DataTable.js
index 55bef3af..eaab5696 100644
--- a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DataTable.js
+++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DataTable.js
@@ -8,7 +8,6 @@ import {
CellMeasurer,
CellMeasurerCache
} from 'react-virtualized'
-
import {
Table,
TBody,
diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DataTable.styles.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DataTable.styles.js
new file mode 100644
index 00000000..838dbad8
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DataTable.styles.js
@@ -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'
+ })
+}
diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DetailsCard.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DetailsCard.js
new file mode 100644
index 00000000..6dc282f5
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DetailsCard.js
@@ -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 {children}
+}
+
+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 (
+
+
+
+
+
+
+ {tx.txClass === 'cashOut' ? : }
+
+ {tx.txClass === 'cashOut' ? 'Cash-out' : 'Cash-in'}
+
+
+
+
+
+
+ {tx.customerPhone && (
+
+ {tx.customerPhone}
+
+ )}
+ {tx.customerIdCardPhotoPath && !tx.customerIdCardData && (
+
+
+
+ )}
+ {tx.customerIdCardData && (
+
+
+
+
+
+
{customer.name}
+
+
+
+
+
{customer.country}
+
+
+
+
+
+
{customer.idCardNumber}
+
+
+
+
{customer.idCardExpirationDate}
+
+
+
+
+ )}
+ {tx.customerFrontCameraPath && (
+
+
+
+ )}
+
+
+
+
+
{crypto > 0 ? displayExRate : '-'}
+
+
+
+
+ {`${commission} ${tx.fiatCode} (${commissionPercentage * 100} %)`}
+
+
+
+
+
+ {tx.txClass === 'cashIn'
+ ? `${Number.parseFloat(tx.cashInFee)} ${tx.fiatCode}`
+ : 'N/A'}
+
+
+
+
+
+
+
+
+ {formatAddress(tx.cryptoCode, tx.toAddress)}
+
+
+
+
+
+
+ {tx.txClass === 'cashOut' ? (
+ 'N/A'
+ ) : (
+ {tx.txHash}
+ )}
+
+
+
+
+ {tx.id}
+
+
+
+
+
+ {getStatus(tx)}
+
+
+
+ )
+}
+
+export default memo(DetailsRow, (prev, next) => prev.id === next.id)
diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DetailsCard.styles.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DetailsCard.styles.js
new file mode 100644
index 00000000..277bcfd2
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/DetailsCard.styles.js
@@ -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
+ }
+}
diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Stripes.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Stripes.js
new file mode 100644
index 00000000..59cf8ce6
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Stripes.js
@@ -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 }) => (
+
+
+ |
+)
+
+export default Stripes
diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Transactions.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Transactions.js
index 75e6f6f7..a4dae14e 100644
--- a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Transactions.js
+++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Transactions.js
@@ -5,7 +5,6 @@ import gql from 'graphql-tag'
import moment from 'moment'
import * as R from 'ramda'
import React, { useEffect, useState } from 'react'
-
import DetailsRow from 'src/pages/Transactions/DetailsCard'
import { mainStyles } from 'src/pages/Transactions/Transactions.styles'
import { getStatus } from 'src/pages/Transactions/helper'
diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/helper.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/helper.js
new file mode 100644
index 00000000..91c0a7b9
--- /dev/null
+++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/helper.js
@@ -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 }
diff --git a/new-lamassu-admin/src/pages/Machines/Machines.js b/new-lamassu-admin/src/pages/Machines/Machines.js
index 43914f98..af8f3fdf 100644
--- a/new-lamassu-admin/src/pages/Machines/Machines.js
+++ b/new-lamassu-admin/src/pages/Machines/Machines.js
@@ -8,7 +8,6 @@ import gql from 'graphql-tag'
import * as R from 'ramda'
import React, { useState, useEffect } from 'react'
import { Link, useLocation } from 'react-router-dom'
-
import { TL1, TL2, Label3 } from 'src/components/typography'
import Cassettes from './MachineComponents/Cassettes'
diff --git a/new-lamassu-admin/src/routing/routes.js b/new-lamassu-admin/src/routing/routes.js
index be3e1c2c..bd176c85 100644
--- a/new-lamassu-admin/src/routing/routes.js
+++ b/new-lamassu-admin/src/routing/routes.js
@@ -51,6 +51,18 @@ const useStyles = makeStyles({
})
const tree = [
+ {
+ key: 'dashboard',
+ label: 'Dashboard',
+ route: '/dashboard',
+ component: Dashboard
+ },
+ {
+ key: 'machines',
+ label: 'Machines',
+ route: '/machines',
+ component: Machines
+ },
{
key: 'transactions',
label: 'Transactions',