diff --git a/new-lamassu-admin/src/pages/Dashboard/Dashboard.js b/new-lamassu-admin/src/pages/Dashboard/Dashboard.js index d446593c..6a6eeb0b 100644 --- a/new-lamassu-admin/src/pages/Dashboard/Dashboard.js +++ b/new-lamassu-admin/src/pages/Dashboard/Dashboard.js @@ -1,7 +1,6 @@ import { useQuery } from '@apollo/react-hooks' import Grid from '@material-ui/core/Grid' import { makeStyles } from '@material-ui/core/styles' -import classnames from 'classnames' import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState } from 'react' @@ -13,6 +12,7 @@ import { H1, Info2, TL2, Label1 } from 'src/components/typography' import AddMachine from 'src/pages/AddMachine' 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 { errorColor } from 'src/styling/variables' import styles from './Dashboard.styles' import Footer from './Footer' @@ -46,20 +46,20 @@ const Dashboard = () => { <>
- <> -
- - Cash-out -
-
- - Cash-in -
- +
+ + Cash-in +
+
+ + Cash-out +
+
+ + + + Action Required +
diff --git a/new-lamassu-admin/src/pages/Dashboard/Dashboard.styles.js b/new-lamassu-admin/src/pages/Dashboard/Dashboard.styles.js index 6526c4a4..a13b54d7 100644 --- a/new-lamassu-admin/src/pages/Dashboard/Dashboard.styles.js +++ b/new-lamassu-admin/src/pages/Dashboard/Dashboard.styles.js @@ -12,18 +12,26 @@ const { label1 } = typographyStyles const styles = { headerLabels: { display: 'flex', - flexDirection: 'row' - }, - headerLabelContainerMargin: { - marginRight: 24 - }, - headerLabelContainer: { - display: 'flex', - alignItems: 'center' - }, - headerLabelSpan: { - extend: label1, - marginLeft: 6 + flexDirection: 'row', + '& > div:first-child': { + display: 'flex', + alignItems: 'center', + marginLeft: 0 + }, + '& > div': { + display: 'flex', + alignItems: 'center', + marginLeft: 25 + }, + '& > div:last-child': { + display: 'flex', + alignItems: 'center', + marginLeft: 64 + }, + '& > div > span': { + extend: label1, + marginLeft: 7 + } }, root: { flexGrow: 1, diff --git a/new-lamassu-admin/src/pages/Dashboard/Footer/Footer.js b/new-lamassu-admin/src/pages/Dashboard/Footer/Footer.js index 2a30909b..5ff9bdd3 100644 --- a/new-lamassu-admin/src/pages/Dashboard/Footer/Footer.js +++ b/new-lamassu-admin/src/pages/Dashboard/Footer/Footer.js @@ -1,3 +1,4 @@ +/* eslint-disable no-unused-vars */ import { useQuery } from '@apollo/react-hooks' import { makeStyles } from '@material-ui/core' import Grid from '@material-ui/core/Grid' @@ -27,19 +28,15 @@ const GET_DATA = gql` } } ` + BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_HALF_UP }) const useStyles = makeStyles(styles) const Footer = () => { const { data } = useQuery(GET_DATA) - const [expanded, setExpanded] = useState(false) - const [delayedExpand, setDelayedExpand] = useState(null) const withCommissions = R.path(['cryptoRates', 'withCommissions'])(data) ?? {} - const classes = useStyles({ - bigFooter: R.keys(withCommissions).length > 8, - expanded - }) + const classes = useStyles() const config = R.path(['config'])(data) ?? {} const canExpand = R.keys(withCommissions).length > 4 @@ -99,31 +96,16 @@ const Footer = () => { ) } - const handleMouseEnter = () => { - setDelayedExpand(setTimeout(() => canExpand && setExpanded(true), 300)) - } - - const handleMouseLeave = () => { - clearTimeout(delayedExpand) - setExpanded(false) - } - return ( - <> -
-
- - +
+
+ + {R.keys(withCommissions).map(key => renderFooterItem(key))}
-
- +
) } diff --git a/new-lamassu-admin/src/pages/Dashboard/Footer/Footer.styles.js b/new-lamassu-admin/src/pages/Dashboard/Footer/Footer.styles.js index 4af67566..ffc26ed8 100644 --- a/new-lamassu-admin/src/pages/Dashboard/Footer/Footer.styles.js +++ b/new-lamassu-admin/src/pages/Dashboard/Footer/Footer.styles.js @@ -17,52 +17,34 @@ const styles = { txOutMargin: { marginLeft: spacer * 3 }, - footer: ({ expanded, bigFooter }) => ({ - height: - expanded && bigFooter - ? spacer * 12 * 3 + spacer * 3 - : expanded - ? spacer * 12 * 2 + spacer * 2 - : spacer * 12, + tickerLabel: { + color: offColor, + marginTop: -5 + }, + footer1: { left: 0, bottom: 0, position: 'fixed', width: '100vw', backgroundColor: white, textAlign: 'left', - boxShadow: '0px -1px 10px 0px rgba(50, 50, 50, 0.1)' - }), - tickerLabel: { - color: offColor, - marginTop: -5 - }, - content: { - width: 1200, - backgroundColor: white, zIndex: 1, - position: 'fixed', - bottom: -spacer, - transform: 'translateY(-100%)' + boxShadow: '0px -1px 10px 0px rgba(50, 50, 50, 0.1)', + minHeight: spacer * 12, + transition: 'min-height 0.5s ease-out', + '&:hover': { + transition: 'min-height 0.5s ease-in', + minHeight: 200 + } }, - footerContainer: ({ expanded, bigFooter }) => ({ - marginLeft: spacer * 5, - height: 100, - marginTop: expanded && bigFooter ? -300 : expanded ? -200 : -100, - overflow: !expanded && 'hidden' - }), - mouseWatcher: ({ expanded, bigFooter }) => ({ - position: 'fixed', - bottom: 0, - left: 0, - width: '100vw', - height: - expanded && bigFooter - ? spacer * 12 * 3 + spacer * 3 - : expanded - ? spacer * 12 * 2 + spacer * 2 - : spacer * 12, - zIndex: 2 - }) + content1: { + width: 1200, + maxHeight: 100, + backgroundColor: white, + zIndex: 2, + bottom: -spacer, + margin: '0 auto' + } } export default styles diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/PercentageChart.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/PercentageChart.js index c51d6e1e..a3d4c1a5 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/PercentageChart.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/PercentageChart.js @@ -8,11 +8,10 @@ import { java, neon, white } from 'src/styling/variables' const styles = { wrapper: { display: 'flex', - height: 130, - marginTop: -8 + height: 142 }, percentageBox: { - height: 130, + height: 142, borderRadius: 4, display: 'flex', alignItems: 'center', @@ -33,11 +32,11 @@ const styles = { borderRadius: 2 }, inWidth: { - width: value => `${value}%` + width: value => `${value}%`, + marginRight: value => (value === 100 ? 0 : 4) }, outWidth: { - width: value => `${100 - value}%`, - marginRight: 4 + width: value => `${100 - value}%` } } @@ -59,14 +58,6 @@ const PercentageChart = ({ cashIn, cashOut }) => { return (
-
- {buildPercentageView(100 - value, 'cashOut')} -
{ )}> {buildPercentageView(value, 'cashIn')}
+
+ {buildPercentageView(100 - value, 'cashOut')} +
) } 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 b825f69c..b9f82f44 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js @@ -45,7 +45,7 @@ const RefLineChart = ({ const svg = d3.select(svgRef.current) const margin = { top: 0, right: 0, bottom: 0, left: 0 } const width = 336 - margin.left - margin.right - const height = 128 - margin.top - margin.bottom + const height = 140 - margin.top - margin.bottom const massageData = () => { // if we're viewing transactions for the past day, then we group by hour. If not, we group by day @@ -148,7 +148,7 @@ const RefLineChart = ({ const y = d3 .scaleLinear() // 30 is a margin so that the labels and the percentage change label can fit and not overlay the line path - .range([height, 30]) + .range([height, 40]) .domain([0, yDomain[1]]) const x = d3 .scaleTime() 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 ace69b0f..cce6dbf2 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js @@ -1,197 +1,363 @@ +import BigNumber from 'bignumber.js' import * as d3 from 'd3' -import { add } from 'date-fns/fp' -import React, { useEffect, useRef, useCallback } from 'react' +import { getTimezoneOffset } from 'date-fns-tz' +import { add, format, startOfWeek, startOfYear } from 'date-fns/fp' +import React, { useCallback, useEffect, useMemo, useRef } from 'react' -import { backgroundColor, java, neon } from 'src/styling/variables' -import { formatDate, toUtc } from 'src/utils/timezones' +import { + java, + neon, + subheaderDarkColor, + offColor, + fontSecondary, + backgroundColor +} from 'src/styling/variables' +import { MINUTE, DAY, WEEK, MONTH } from 'src/utils/time' -const RefScatterplot = ({ data: realData, timeFrame, timezone }) => { - const svgRef = useRef() - const drawGraph = useCallback(() => { - const svg = d3.select(svgRef.current) - const margin = { top: 25, right: 0, bottom: 25, left: 15 } - const width = 555 - margin.left - margin.right - const height = 150 - margin.top - margin.bottom - // finds maximum value for the Y axis. Minimum value is 100. If value is multiple of 1000, add 100 - // (this is because the Y axis looks best with multiples of 100) - const findMaxY = () => { - if (realData.length === 0) return 100 - const maxvalueTx = - 100 * Math.ceil(d3.max(realData, t => parseFloat(t.fiat)) / 100) - const maxY = Math.max(100, maxvalueTx) - if (maxY % 1000 === 0) return maxY + 100 - return maxY - } +const Graph = ({ data, timeFrame, timezone }) => { + const ref = useRef(null) - const timeFormat = v => { - switch (timeFrame) { - case 'Week': - return d3.timeFormat('%a %d')(v) - case 'Month': - return d3.timeFormat('%b %d')(v) - default: - return formatDate(v, timezone, 'HH:mm') + const GRAPH_HEIGHT = 250 + const GRAPH_WIDTH = 555 + const GRAPH_MARGIN = useMemo( + () => ({ + top: 20, + right: 0.5, + bottom: 27, + left: 43.5 + }), + [] + ) + + const offset = getTimezoneOffset(timezone) + const NOW = Date.now() + offset + + const periodDomains = { + Day: [NOW - DAY, NOW], + Week: [NOW - WEEK, NOW], + Month: [NOW - MONTH, NOW] + } + + const dataPoints = useMemo( + () => ({ + Day: { + freq: 24, + step: 60 * 60 * 1000, + tick: d3.utcHour.every(4), + labelFormat: '%H:%M' + }, + Week: { + freq: 7, + step: 24 * 60 * 60 * 1000, + tick: d3.utcDay.every(1), + labelFormat: '%a %d' + }, + Month: { + freq: 30, + step: 24 * 60 * 60 * 1000, + tick: d3.utcDay.every(2), + labelFormat: '%d' } - } + }), + [] + ) - // changes values of arguments in some d3 function calls to make the graph labels look good according to the selected time frame - const findXAxisSettings = () => { - switch (timeFrame) { - case 'Week': - return { - nice: 7, - ticks: 7, - subtractDays: 7, - timeRange: [50, 500] - } - case 'Month': - return { - nice: 6, - ticks: 6, - subtractDays: 30, - timeRange: [50, 500] - } - default: - return { - nice: null, - ticks: 4, - subtractDays: 1, - timeRange: [50, 500] - } + const getPastAndCurrentDayLabels = useCallback(d => { + const currentDate = new Date(d) + const currentDateDay = currentDate.getUTCDate() + const currentDateWeekday = currentDate.getUTCDay() + const currentDateMonth = currentDate.getUTCMonth() + + const previousDate = new Date(currentDate.getTime()) + previousDate.setUTCDate(currentDateDay - 1) + + const previousDateDay = previousDate.getUTCDate() + const previousDateWeekday = previousDate.getUTCDay() + const previousDateMonth = previousDate.getUTCMonth() + + const daysOfWeek = Array.from(Array(7)).map((_, i) => + format('EEE', add({ days: i }, startOfWeek(new Date()))) + ) + + const months = Array.from(Array(12)).map((_, i) => + format('LLL', add({ months: i }, startOfYear(new Date()))) + ) + + return { + previous: + currentDateMonth !== previousDateMonth + ? months[previousDateMonth] + : `${daysOfWeek[previousDateWeekday]} ${previousDateDay}`, + current: + currentDateMonth !== previousDateMonth + ? months[currentDateMonth] + : `${daysOfWeek[currentDateWeekday]} ${currentDateDay}` + } + }, []) + + const buildTicks = useCallback( + domain => { + const points = [] + + const roundDate = d => { + const step = dataPoints[timeFrame].step + return new Date(Math.ceil(d.valueOf() / step) * step) } - } - // sets width of the graph - svg.attr('width', width) + for (let i = 0; i <= dataPoints[timeFrame].freq; i++) { + const stepDate = new Date(NOW - i * dataPoints[timeFrame].step) + if (roundDate(stepDate) > domain[1]) continue + if (stepDate < domain[0]) continue + points.push(roundDate(stepDate)) + } - // background color for the graph - svg - .append('rect') - .attr('x', 0) - .attr('y', 0) - .attr('width', width) - .attr('height', height + margin.top) - .attr('fill', backgroundColor) + return points + }, + [NOW, dataPoints, timeFrame] + ) - // declare g variable where more svg components will be attached - const g = svg - .append('g') - .attr('transform', `translate(${margin.left},${margin.top})`) + const x = d3 + .scaleUtc() + .domain(periodDomains[timeFrame]) + .range([GRAPH_MARGIN.left, GRAPH_WIDTH - GRAPH_MARGIN.right]) - // y axis range: round up to 100 highest data value, if rounds up to 1000, add 100. - // this keeps the vertical axis nice looking - const maxY = findMaxY() - const xAxisSettings = findXAxisSettings() + const y = d3 + .scaleLinear() + .domain([ + 0, + (d3.max(data, d => new BigNumber(d.fiat).toNumber()) ?? 1000) * 1.05 + ]) + .nice() + .range([GRAPH_HEIGHT - GRAPH_MARGIN.bottom, GRAPH_MARGIN.top]) - // y and x scales - const y = d3 - .scaleLinear() - .range([height, 0]) - .domain([0, maxY]) - .nice(3) - const x = d3 - .scaleTime() - .domain([ - add({ days: -xAxisSettings.subtractDays }, new Date()).valueOf(), - new Date().valueOf() - ]) - .range(xAxisSettings.timeRange) - .nice(xAxisSettings.nice) + const buildBackground = useCallback( + g => { + g.append('rect') + .attr('x', 0) + .attr('y', GRAPH_MARGIN.top) + .attr('width', GRAPH_WIDTH) + .attr('height', GRAPH_HEIGHT - GRAPH_MARGIN.top - GRAPH_MARGIN.bottom) + .attr('fill', backgroundColor) + }, + [GRAPH_MARGIN] + ) - const timeValue = s => { - const date = toUtc(s) - return x(date.valueOf()) - } + const buildXAxis = useCallback( + g => + g + .attr( + 'transform', + `translate(0, ${GRAPH_HEIGHT - GRAPH_MARGIN.bottom})` + ) + .call( + d3 + .axisBottom(x) + .ticks(dataPoints[timeFrame].tick) + .tickFormat(d => { + return d3.timeFormat(dataPoints[timeFrame].labelFormat)( + d.getTime() + d.getTimezoneOffset() * MINUTE + ) + }) + ) + .call(g => g.select('.domain').remove()), + [GRAPH_MARGIN, dataPoints, timeFrame, x] + ) - // horizontal gridlines - const makeYGridlines = () => { - return d3.axisLeft(y).ticks(4) - } - g.append('g') - .style('color', '#eef1ff') - .call( - makeYGridlines() - .tickSize(-width) - .tickFormat('') - ) - .call(g => g.select('.domain').remove()) + const buildYAxis = useCallback( + g => + g + .attr('transform', `translate(${GRAPH_MARGIN.left}, 0)`) + .call(d3.axisLeft(y).ticks(5)) + .call(g => g.select('.domain').remove()) + .selectAll('text') + .attr('dy', '-0.25rem'), + [GRAPH_MARGIN, y] + ) - /* X AXIS */ - // this one is for the labels at the bottom - g.append('g') - .attr('transform', 'translate(0,' + height + ')') - .style('font-size', '13px') - .style('color', '#5f668a') - .style('font-family', 'MuseoSans') - .style('margin-top', '11px') - .call( - d3 - .axisBottom(x) - .ticks(xAxisSettings.ticks) - .tickSize(0) - .tickFormat(timeFormat) - ) - .selectAll('text') - .attr('dy', '1.5em') - // this is for the x axis line. It is the same color as the horizontal grid lines - g.append('g') - .attr('transform', 'translate(0,' + height + ')') - .style('color', '#eef1ff') - .call( - d3 - .axisBottom(x) - .ticks(6) - .tickSize(0) - .tickFormat('') - ) - .selectAll('text') - .attr('dy', '1.5em') + const buildGrid = useCallback( + g => { + g.attr('stroke', subheaderDarkColor) + .attr('fill', subheaderDarkColor) + // Vertical lines + .call(g => + g + .append('g') + .selectAll('line') + .data(buildTicks(x.domain())) + .join('line') + .attr('x1', d => 0.5 + x(d)) + .attr('x2', d => 0.5 + x(d)) + .attr('y1', GRAPH_MARGIN.top) + .attr('y2', GRAPH_HEIGHT - GRAPH_MARGIN.bottom) + .attr('stroke-width', 1) + ) + // Horizontal lines + .call(g => + g + .append('g') + .selectAll('line') + .data( + d3 + .axisLeft(y) + .scale() + .ticks(5) + ) + .join('line') + .attr('y1', d => 0.5 + y(d)) + .attr('y2', d => 0.5 + y(d)) + .attr('x1', GRAPH_MARGIN.left) + .attr('x2', GRAPH_WIDTH - GRAPH_MARGIN.right) + ) + // Thick vertical lines + .call(g => + g + .append('g') + .selectAll('line') + .data( + buildTicks(x.domain()).filter(x => { + if (timeFrame === 'day') return x.getUTCHours() === 0 + return x.getUTCDate() === 1 + }) + ) + .join('line') + .attr('class', 'dateSeparator') + .attr('x1', d => 0.5 + x(d)) + .attr('x2', d => 0.5 + x(d)) + .attr('y1', GRAPH_MARGIN.top - 10) + .attr('y2', GRAPH_HEIGHT - GRAPH_MARGIN.bottom) + .attr('stroke-width', 2) + .join('text') + ) + // Left side breakpoint label + .call(g => { + const separator = d3 + ?.select('.dateSeparator') + ?.node() + ?.getBBox() - // Y axis - g.append('g') - .style('font-size', '13px') - .style('color', '#5f668a') - .style('font-family', 'MuseoSans') - .style('margin-top', '11px') - .call( - d3 - .axisLeft(y) - .ticks(4) - .tickSize(0) - ) - .call(g => g.select('.domain').remove()) - .selectAll('text') - .attr('dy', '-0.40em') - .attr('dx', '3em') + if (!separator) return - // Append dots - const dots = svg - .append('g') - .attr('transform', `translate(${margin.left},${margin.top})`) + const breakpoint = buildTicks(x.domain()).filter(x => { + if (timeFrame === 'day') return x.getUTCHours() === 0 + return x.getUTCDate() === 1 + }) - dots - .selectAll('circle') - .data(realData) - .enter() - .append('circle') - .attr('cx', d => timeValue(d.created)) - .attr('cy', d => y(d.fiat)) - .attr('r', 4) - .style('fill', d => (d.txClass === 'cashIn' ? java : neon)) - }, [realData, timeFrame, timezone]) + const labels = getPastAndCurrentDayLabels(breakpoint) + + return g + .append('text') + .attr('x', separator.x - 7) + .attr('y', separator.y) + .attr('text-anchor', 'end') + .attr('dy', '.25em') + .text(labels.previous) + }) + // Right side breakpoint label + .call(g => { + const separator = d3 + ?.select('.dateSeparator') + ?.node() + ?.getBBox() + + if (!separator) return + + const breakpoint = buildTicks(x.domain()).filter(x => { + if (timeFrame === 'day') return x.getUTCHours() === 0 + return x.getUTCDate() === 1 + }) + + const labels = getPastAndCurrentDayLabels(breakpoint) + + return g + .append('text') + .attr('x', separator.x + 7) + .attr('y', separator.y) + .attr('text-anchor', 'start') + .attr('dy', '.25em') + .text(labels.current) + }) + }, + [GRAPH_MARGIN, buildTicks, getPastAndCurrentDayLabels, x, y, timeFrame] + ) + + const formatTicksText = useCallback( + () => + d3 + .selectAll('.tick text') + .style('stroke', offColor) + .style('fill', offColor) + .style('stroke-width', 0) + .style('font-family', fontSecondary), + [] + ) + + const formatText = useCallback( + () => + d3 + .selectAll('text') + .style('stroke', offColor) + .style('fill', offColor) + .style('stroke-width', 0) + .style('font-family', fontSecondary), + [] + ) + + const formatTicks = useCallback(() => { + d3.selectAll('.tick line') + .style('stroke', 'transparent') + .style('fill', 'transparent') + }, []) + + const drawData = useCallback( + g => { + g.selectAll('circle') + .data(data) + .join('circle') + .attr('cx', d => { + const created = new Date(d.created) + return x(created.setTime(created.getTime() + offset)) + }) + .attr('cy', d => y(new BigNumber(d.fiat).toNumber())) + .attr('fill', d => (d.txClass === 'cashIn' ? java : neon)) + .attr('r', 3.5) + }, + [data, offset, x, y] + ) + + const drawChart = useCallback(() => { + const svg = d3 + .select(ref.current) + .attr('viewBox', [0, 0, GRAPH_WIDTH, GRAPH_HEIGHT]) + + svg.append('g').call(buildBackground) + svg.append('g').call(buildGrid) + svg.append('g').call(buildXAxis) + svg.append('g').call(buildYAxis) + svg.append('g').call(formatTicksText) + svg.append('g').call(formatText) + svg.append('g').call(formatTicks) + svg.append('g').call(drawData) + + return svg.node() + }, [ + buildBackground, + buildGrid, + buildXAxis, + buildYAxis, + drawData, + formatText, + formatTicks, + formatTicksText + ]) useEffect(() => { - // first we clear old chart DOM elements on component update - d3.select(svgRef.current) + d3.select(ref.current) .selectAll('*') .remove() - drawGraph() - }, [drawGraph]) + drawChart() + }, [drawChart]) - return ( - <> - - - ) + return } -export default RefScatterplot + +export default Graph diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js index 500c1bd8..341f3385 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js @@ -9,10 +9,11 @@ import * as R from 'ramda' import React, { useState } from 'react' import { EmptyTable } from 'src/components/table' -import { Label1, Label2 } from 'src/components/typography/index' +import { Label1, Label2, P } from 'src/components/typography/index' import { ReactComponent as PercentDownIcon } from 'src/styling/icons/dashboard/down.svg' import { ReactComponent as PercentNeutralIcon } from 'src/styling/icons/dashboard/equal.svg' import { ReactComponent as PercentUpIcon } from 'src/styling/icons/dashboard/up.svg' +import { java, neon } from 'src/styling/variables' import { fromNamespace } from 'src/utils/config' import { toTimezone } from 'src/utils/timezones' @@ -199,9 +200,27 @@ const SystemPerformance = () => { {/* todo new customers */} - + - Transactions +
+ Transactions +
+

{timezone} timezone

+ +
+ + + + In +
+
+ + + + Out +
+
+
{ />
- + - + Profit from commissions
@@ -233,23 +252,22 @@ const SystemPerformance = () => { /> - - - Direction - - -
- Out - - -
- In - + + Direction +
+
+ + + + In +
+
+ + + + Out +
+
div': { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + marginLeft: 15, + '&:first-child': { + marginLeft: 0 + }, + '& > p': { + marginLeft: 8 + } + } + }, + txGraphContainer: { + height: 300, + marginTop: 30 + }, + commissionsGraphContainer: { + height: 250, + marginTop: 30 + }, + verticalLine: { + height: 15, + width: 1, + backgroundColor: offDarkColor, + marginLeft: 31, + marginRight: 16 } } diff --git a/new-lamassu-admin/src/pages/Locales/helper.js b/new-lamassu-admin/src/pages/Locales/helper.js index 3158402e..f4e9aa76 100644 --- a/new-lamassu-admin/src/pages/Locales/helper.js +++ b/new-lamassu-admin/src/pages/Locales/helper.js @@ -2,7 +2,7 @@ import * as R from 'ramda' import * as Yup from 'yup' import Autocomplete from 'src/components/inputs/formik/Autocomplete.js' -import timezoneList from 'src/utils/timezone-list' +import { labels as timezoneList } from 'src/utils/timezone-list' const getFields = (getData, names, onChange, auxElements = []) => { return R.filter( diff --git a/new-lamassu-admin/src/utils/timezone-list.js b/new-lamassu-admin/src/utils/timezone-list.js index 848cea87..c2d681cd 100644 --- a/new-lamassu-admin/src/utils/timezone-list.js +++ b/new-lamassu-admin/src/utils/timezone-list.js @@ -3,85 +3,89 @@ import { getTimezoneOffset } from 'date-fns-tz' import * as R from 'ramda' const timezones = { - 'Pacific/Midway': 'Midway Island, Samoa', - 'Pacific/Honolulu': 'Hawaii', - 'America/Juneau': 'Alaska', - 'America/Boise': 'Mountain Time', - 'America/Dawson': 'Dawson, Yukon', - 'America/Chihuahua': 'Chihuahua, La Paz, Mazatlan', - 'America/Phoenix': 'Arizona', - 'America/Chicago': 'Central Time', - 'America/Regina': 'Saskatchewan', - 'America/Mexico_City': 'Guadalajara, Mexico City, Monterrey', - 'America/Belize': 'Central America', - 'America/Detroit': 'Eastern Time', - 'America/Bogota': 'Bogota, Lima, Quito', - 'America/Caracas': 'Caracas, La Paz', - 'America/Santiago': 'Santiago', - 'America/St_Johns': 'Newfoundland and Labrador', - 'America/Sao_Paulo': 'Brasilia', - 'America/Tijuana': 'Tijuana', - 'America/Montevideo': 'Montevideo', - 'America/Argentina/Buenos_Aires': 'Buenos Aires, Georgetown', - 'America/Godthab': 'Greenland', - 'America/Los_Angeles': 'Pacific Time', - 'Atlantic/Azores': 'Azores', - 'Atlantic/Cape_Verde': 'Cape Verde Islands', - GMT: 'UTC', - 'Europe/London': 'Edinburgh, London', - 'Europe/Dublin': 'Dublin', - 'Europe/Lisbon': 'Lisbon', - 'Africa/Casablanca': 'Casablanca, Monrovia', - 'Atlantic/Canary': 'Canary Islands', - 'Europe/Belgrade': 'Belgrade, Bratislava, Budapest, Ljubljana, Prague', - 'Europe/Sarajevo': 'Sarajevo, Skopje, Warsaw, Zagreb', - 'Europe/Brussels': 'Brussels, Copenhagen, Madrid, Paris', - 'Europe/Amsterdam': 'Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna', - 'Africa/Algiers': 'West Central Africa', - 'Europe/Bucharest': 'Bucharest', - 'Africa/Cairo': 'Cairo', - 'Europe/Helsinki': 'Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius', - 'Europe/Athens': 'Athens, Istanbul, Minsk', - 'Asia/Jerusalem': 'Jerusalem', - 'Africa/Harare': 'Harare, Pretoria', - 'Europe/Moscow': 'Moscow, St. Petersburg, Volgograd', - 'Asia/Kuwait': 'Kuwait, Riyadh', - 'Africa/Nairobi': 'Nairobi', - 'Asia/Baghdad': 'Baghdad', - 'Asia/Tehran': 'Tehran', - 'Asia/Dubai': 'Abu Dhabi, Muscat', - 'Asia/Baku': 'Baku, Tbilisi, Yerevan', - 'Asia/Kabul': 'Kabul', - 'Asia/Yekaterinburg': 'Ekaterinburg', - 'Asia/Karachi': 'Islamabad, Karachi, Tashkent', - 'Asia/Kolkata': 'Chennai, Kolkata, Mumbai, New Delhi', - 'Asia/Kathmandu': 'Kathmandu', - 'Asia/Dhaka': 'Astana, Dhaka', - 'Asia/Colombo': 'Sri Jayawardenepura', - 'Asia/Almaty': 'Almaty, Novosibirsk', - 'Asia/Rangoon': 'Yangon Rangoon', - 'Asia/Bangkok': 'Bangkok, Hanoi, Jakarta', - 'Asia/Krasnoyarsk': 'Krasnoyarsk', - 'Asia/Shanghai': 'Beijing, Chongqing, Hong Kong SAR, Urumqi', - 'Asia/Kuala_Lumpur': 'Kuala Lumpur, Singapore', - 'Asia/Taipei': 'Taipei', - 'Australia/Perth': 'Perth', - 'Asia/Irkutsk': 'Irkutsk, Ulaanbaatar', - 'Asia/Seoul': 'Seoul', - 'Asia/Tokyo': 'Osaka, Sapporo, Tokyo', - 'Asia/Yakutsk': 'Yakutsk', - 'Australia/Darwin': 'Darwin', - 'Australia/Adelaide': 'Adelaide', - 'Australia/Sydney': 'Canberra, Melbourne, Sydney', - 'Australia/Brisbane': 'Brisbane', - 'Australia/Hobart': 'Hobart', - 'Asia/Vladivostok': 'Vladivostok', - 'Pacific/Guam': 'Guam, Port Moresby', - 'Asia/Magadan': 'Magadan, Solomon Islands, New Caledonia', - 'Asia/Kamchatka': 'Kamchatka, Marshall Islands', - 'Pacific/Fiji': 'Fiji Islands', - 'Pacific/Auckland': 'Auckland, Wellington', - 'Pacific/Tongatapu': "Nuku'alofa" + 'Pacific/Midway': { short: 'SST', long: 'Midway Island, Samoa' }, + 'Pacific/Honolulu': { short: 'HAST', long: 'Hawaii' }, + 'America/Juneau': { short: 'AKST', long: 'Alaska' }, + 'America/Boise': { long: 'Mountain Time' }, + 'America/Dawson': { long: 'Dawson, Yukon' }, + 'America/Chihuahua': { long: 'Chihuahua, La Paz, Mazatlan' }, + 'America/Phoenix': { long: 'Arizona' }, + 'America/Chicago': { long: 'Central Time' }, + 'America/Regina': { long: 'Saskatchewan' }, + 'America/Mexico_City': { long: 'Guadalajara, Mexico City, Monterrey' }, + 'America/Belize': { long: 'Central America' }, + 'America/Detroit': { long: 'Eastern Time' }, + 'America/Bogota': { long: 'Bogota, Lima, Quito' }, + 'America/Caracas': { long: 'Caracas, La Paz' }, + 'America/Santiago': { long: 'Santiago' }, + 'America/St_Johns': { long: 'Newfoundland and Labrador' }, + 'America/Sao_Paulo': { long: 'Brasilia' }, + 'America/Tijuana': { long: 'Tijuana' }, + 'America/Montevideo': { long: 'Montevideo' }, + 'America/Argentina/Buenos_Aires': { long: 'Buenos Aires, Georgetown' }, + 'America/Godthab': { long: 'Greenland' }, + 'America/Los_Angeles': { long: 'Pacific Time' }, + 'Atlantic/Azores': { long: 'Azores' }, + 'Atlantic/Cape_Verde': { long: 'Cape Verde Islands' }, + GMT: { long: 'UTC' }, + 'Europe/London': { long: 'Edinburgh, London' }, + 'Europe/Dublin': { long: 'Dublin' }, + 'Europe/Lisbon': { long: 'Lisbon' }, + 'Africa/Casablanca': { long: 'Casablanca, Monrovia' }, + 'Atlantic/Canary': { long: 'Canary Islands' }, + 'Europe/Belgrade': { + long: 'Belgrade, Bratislava, Budapest, Ljubljana, Prague' + }, + 'Europe/Sarajevo': { long: 'Sarajevo, Skopje, Warsaw, Zagreb' }, + 'Europe/Brussels': { long: 'Brussels, Copenhagen, Madrid, Paris' }, + 'Europe/Amsterdam': { + long: 'Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna' + }, + 'Africa/Algiers': { long: 'West Central Africa' }, + 'Europe/Bucharest': { long: 'Bucharest' }, + 'Africa/Cairo': { long: 'Cairo' }, + 'Europe/Helsinki': { long: 'Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius' }, + 'Europe/Athens': { long: 'Athens, Istanbul, Minsk' }, + 'Asia/Jerusalem': { long: 'Jerusalem' }, + 'Africa/Harare': { long: 'Harare, Pretoria' }, + 'Europe/Moscow': { long: 'Moscow, St. Petersburg, Volgograd' }, + 'Asia/Kuwait': { long: 'Kuwait, Riyadh' }, + 'Africa/Nairobi': { long: 'Nairobi' }, + 'Asia/Baghdad': { long: 'Baghdad' }, + 'Asia/Tehran': { long: 'Tehran' }, + 'Asia/Dubai': { long: 'Abu Dhabi, Muscat' }, + 'Asia/Baku': { long: 'Baku, Tbilisi, Yerevan' }, + 'Asia/Kabul': { long: 'Kabul' }, + 'Asia/Yekaterinburg': { long: 'Ekaterinburg' }, + 'Asia/Karachi': { long: 'Islamabad, Karachi, Tashkent' }, + 'Asia/Kolkata': { long: 'Chennai, Kolkata, Mumbai, New Delhi' }, + 'Asia/Kathmandu': { long: 'Kathmandu' }, + 'Asia/Dhaka': { long: 'Astana, Dhaka' }, + 'Asia/Colombo': { long: 'Sri Jayawardenepura' }, + 'Asia/Almaty': { long: 'Almaty, Novosibirsk' }, + 'Asia/Rangoon': { long: 'Yangon Rangoon' }, + 'Asia/Bangkok': { long: 'Bangkok, Hanoi, Jakarta' }, + 'Asia/Krasnoyarsk': { long: 'Krasnoyarsk' }, + 'Asia/Shanghai': { long: 'Beijing, Chongqing, Hong Kong SAR, Urumqi' }, + 'Asia/Kuala_Lumpur': { long: 'Kuala Lumpur, Singapore' }, + 'Asia/Taipei': { long: 'Taipei' }, + 'Australia/Perth': { long: 'Perth' }, + 'Asia/Irkutsk': { long: 'Irkutsk, Ulaanbaatar' }, + 'Asia/Seoul': { long: 'Seoul' }, + 'Asia/Tokyo': { long: 'Osaka, Sapporo, Tokyo' }, + 'Asia/Yakutsk': { long: 'Yakutsk' }, + 'Australia/Darwin': { long: 'Darwin' }, + 'Australia/Adelaide': { long: 'Adelaide' }, + 'Australia/Sydney': { long: 'Canberra, Melbourne, Sydney' }, + 'Australia/Brisbane': { long: 'Brisbane' }, + 'Australia/Hobart': { long: 'Hobart' }, + 'Asia/Vladivostok': { long: 'Vladivostok' }, + 'Pacific/Guam': { long: 'Guam, Port Moresby' }, + 'Asia/Magadan': { long: 'Magadan, Solomon Islands, New Caledonia' }, + 'Asia/Kamchatka': { long: 'Kamchatka, Marshall Islands' }, + 'Pacific/Fiji': { long: 'Fiji Islands' }, + 'Pacific/Auckland': { long: 'Auckland, Wellington' }, + 'Pacific/Tongatapu': { long: "Nuku'alofa" } } const buildTzLabels = timezoneList => { @@ -106,7 +110,7 @@ const buildTzLabels = timezoneList => { const prefix = `(GMT${isNegative ? `-` : `+`}${hours}:${minutes})` acc.push({ - label: `${prefix} - ${value[1]}`, + label: `${prefix} - ${value[1].long}`, code: value[0] }) @@ -117,4 +121,6 @@ const buildTzLabels = timezoneList => { ) } -export default buildTzLabels(timezones) +const labels = buildTzLabels(timezones) + +export { labels, timezones }