Merge pull request #1013 from chaotixkilla/fix-change-dashboard-ui

Dashboard UI changes
This commit is contained in:
Rafael Taranto 2021-12-23 11:02:58 +00:00 committed by GitHub
commit dd09ae5a7e
12 changed files with 614 additions and 424 deletions

View file

@ -7,8 +7,8 @@ import { useHistory } from 'react-router-dom'
import { P } from 'src/components/typography/index'
import { ReactComponent as Wrench } from 'src/styling/icons/action/wrench/zodiac.svg'
import { ReactComponent as LinkIcon } from 'src/styling/icons/button/link/zodiac.svg'
import { ReactComponent as CashBoxEmpty } from 'src/styling/icons/cassettes/cashbox-empty.svg'
import { ReactComponent as AlertLinkIcon } from 'src/styling/icons/month arrows/right.svg'
import { ReactComponent as WarningIcon } from 'src/styling/icons/warning-icon/tomato.svg'
import styles from './Alerts.styles'
@ -49,7 +49,7 @@ const AlertsTable = ({ numToRender, alerts, machines }) => {
<Wrench style={{ height: 23, width: 23, marginRight: 8 }} />
)}
<P className={classes.listItemText}>{alertMessage(alert)}</P>
<LinkIcon
<AlertLinkIcon
className={classes.linkIcon}
onClick={() => history.push(links[alert.type] || '/dashboard')}
/>

View file

@ -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 = () => {
<>
<TitleSection title="Dashboard">
<div className={classes.headerLabels}>
<>
<div
className={classnames(
classes.headerLabelContainer,
classes.headerLabelContainerMargin
)}>
<TxOutIcon />
<span className={classes.headerLabelSpan}>Cash-out</span>
</div>
<div className={classes.headerLabelContainer}>
<TxInIcon />
<span className={classes.headerLabelSpan}>Cash-in</span>
</div>
</>
<div>
<TxInIcon />
<span>Cash-in</span>
</div>
<div>
<TxOutIcon />
<span>Cash-out</span>
</div>
<div>
<svg width={12} height={12}>
<rect width={12} height={12} rx={3} fill={errorColor} />
</svg>
<span>Action Required</span>
</div>
</div>
</TitleSection>
<div className={classes.root}>

View file

@ -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,

View file

@ -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 (
<>
<div
className={classes.mouseWatcher}
onMouseLeave={handleMouseLeave}
onMouseEnter={handleMouseEnter}
/>
<div className={classes.content}>
<Grid container spacing={1}>
<Grid container className={classes.footerContainer}>
<div className={classes.footer1}>
<div className={classes.content1}>
<Grid container>
<Grid container className={classes.footerContainer1}>
{R.keys(withCommissions).map(key => renderFooterItem(key))}
</Grid>
</Grid>
</div>
<div className={classes.footer} />
</>
</div>
)
}

View file

@ -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

View file

@ -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 (
<div className={classes.wrapper}>
<div
className={classnames(
percentageClasses,
classes.outColor,
classes.outWidth
)}>
{buildPercentageView(100 - value, 'cashOut')}
</div>
<div
className={classnames(
percentageClasses,
@ -75,6 +66,14 @@ const PercentageChart = ({ cashIn, cashOut }) => {
)}>
{buildPercentageView(value, 'cashIn')}
</div>
<div
className={classnames(
percentageClasses,
classes.outColor,
classes.outWidth
)}>
{buildPercentageView(100 - value, 'cashOut')}
</div>
</div>
)
}

View file

@ -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()

View file

@ -1,197 +1,357 @@
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 filterDay = useMemo(
x => (timeFrame === 'day' ? x.getUTCHours() === 0 : x.getUTCDate() === 1),
[timeFrame]
)
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(filterDay))
.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(filterDay)
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(filterDay)
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, filterDay]
)
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 (
<>
<svg ref={svgRef} />
</>
)
return <svg ref={ref} />
}
export default RefScatterplot
export default Graph

View file

@ -9,11 +9,13 @@ 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 { timezones } from 'src/utils/timezone-list'
import { toTimezone } from 'src/utils/timezones'
import PercentageChart from './Graphs/PercentageChart'
@ -199,9 +201,30 @@ const SystemPerformance = () => {
</Grid>
{/* todo new customers */}
</Grid>
<Grid container className={classes.gridContainer}>
<Grid container className={classes.txGraphContainer}>
<Grid item xs={12}>
<Label2>Transactions</Label2>
<div className={classes.graphHeader}>
<Label2 noMargin>Transactions</Label2>
<div className={classes.labelWrapper}>
<P noMargin>
{timezones[timezone].short ?? timezones[timezone].long}{' '}
timezone
</P>
<span className={classes.verticalLine} />
<div>
<svg width={8} height={8}>
<rect width={8} height={8} rx={4} fill={java} />
</svg>
<Label1 noMargin>In</Label1>
</div>
<div>
<svg width={8} height={8}>
<rect width={8} height={8} rx={4} fill={neon} />
</svg>
<Label1 noMargin>Out</Label1>
</div>
</div>
</div>
<Scatterplot
timeFrame={selectedRange}
data={transactionsToShow}
@ -209,9 +232,9 @@ const SystemPerformance = () => {
/>
</Grid>
</Grid>
<Grid container className={classes.gridContainer}>
<Grid container className={classes.commissionGraphContainer}>
<Grid item xs={8}>
<Label2 className={classes.labelMargin}>
<Label2 noMargin className={classes.commissionProfitTitle}>
Profit from commissions
</Label2>
<div className={classes.profitContainer}>
@ -233,23 +256,22 @@ const SystemPerformance = () => {
/>
</Grid>
<Grid item xs={4}>
<Grid container>
<Grid item>
<Label2 className={classes.labelMargin}>Direction</Label2>
</Grid>
<Grid
item
className={classnames(
classes.directionLabelContainer,
classes.dirLabContMargin
)}>
<div className={classes.outSquare} />
<Label1 className={classes.directionLabel}>Out</Label1>
</Grid>
<Grid item className={classes.directionLabelContainer}>
<div className={classes.inSquare} />
<Label1 className={classes.directionLabel}>In</Label1>
</Grid>
<Grid container className={classes.graphHeader}>
<Label2 noMargin>Direction</Label2>
<div className={classes.labelWrapper}>
<div>
<svg width={8} height={8}>
<rect width={8} height={8} rx={2} fill={java} />
</svg>
<Label1 noMargin>In</Label1>
</div>
<div>
<svg width={8} height={8}>
<rect width={8} height={8} rx={2} fill={neon} />
</svg>
<Label1 noMargin>Out</Label1>
</div>
</div>
</Grid>
<Grid item xs>
<PercentageChart

View file

@ -1,5 +1,6 @@
import {
offColor,
offDarkColor,
spacer,
primaryColor,
fontSize3,
@ -7,8 +8,6 @@ import {
fontColor,
spring4,
tomato,
java,
neon,
comet
} from 'src/styling/variables'
@ -67,12 +66,6 @@ const styles = {
navContainer: {
display: 'flex'
},
profitLabel: {
fontSize: fontSize3,
fontFamily: fontSecondary,
fontWeight: 700,
color: fontColor
},
percentUp: {
fontSize: fontSize3,
fontFamily: fontSecondary,
@ -96,34 +89,14 @@ const styles = {
profitContainer: {
display: 'flex',
justifyContent: 'space-between',
margin: '0 26px -30px 16px',
margin: '23px 26px -30px 16px',
position: 'relative'
},
gridContainer: {
marginTop: 30,
height: 225
},
inSquare: {
width: 8,
height: 8,
borderRadius: 2,
marginTop: 18,
marginRight: 4,
backgroundColor: java
},
outSquare: {
width: 8,
height: 8,
borderRadius: 2,
marginTop: 18,
marginRight: 4,
backgroundColor: neon
},
directionLabelContainer: {
display: 'flex'
},
dirLabContMargin: {
marginRight: 20
profitLabel: {
fontSize: fontSize3,
fontFamily: fontSecondary,
fontWeight: 700,
color: fontColor
},
directionIcon: {
width: 16,
@ -131,12 +104,50 @@ const styles = {
marginBottom: -2,
marginRight: 4
},
labelMargin: {
marginBottom: 20,
marginRight: 32
},
emptyTransactions: {
paddingTop: 40
},
commissionProfitTitle: {
marginBottom: 16
},
graphHeader: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 16
},
labelWrapper: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
'& > 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
}
}

View file

@ -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(

View file

@ -3,85 +3,109 @@ 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': { short: 'MST', long: 'Mountain Time' },
'America/Dawson': { short: 'MST', long: 'Dawson, Yukon' },
'America/Chihuahua': { short: null, long: 'Chihuahua, La Paz, Mazatlan' },
'America/Phoenix': { short: 'MST', long: 'Arizona' },
'America/Chicago': { short: 'CST', long: 'Central Time' },
'America/Regina': { short: 'CST', long: 'Saskatchewan' },
'America/Mexico_City': {
short: 'CST',
long: 'Guadalajara, Mexico City, Monterrey'
},
'America/Belize': { short: 'CST', long: 'Central America' },
'America/Detroit': { short: 'EST', long: 'Eastern Time' },
'America/Bogota': { short: 'COT', long: 'Bogota, Lima, Quito' },
'America/Caracas': { short: 'VET', long: 'Caracas, La Paz' },
'America/Santiago': { short: 'CLST', long: 'Santiago' },
'America/St_Johns': { short: 'HNTN', long: 'Newfoundland and Labrador' },
'America/Sao_Paulo': { short: 'BRT', long: 'Brasilia' },
'America/Tijuana': { short: 'PST', long: 'Tijuana' },
'America/Montevideo': { short: 'UYT', long: 'Montevideo' },
'America/Argentina/Buenos_Aires': {
short: null,
long: 'Buenos Aires, Georgetown'
},
'America/Godthab': { short: null, long: 'Greenland' },
'America/Los_Angeles': { short: 'PST', long: 'Pacific Time' },
'Atlantic/Azores': { short: 'AZOT', long: 'Azores' },
'Atlantic/Cape_Verde': { short: 'CVT', long: 'Cape Verde Islands' },
GMT: { short: 'GMT', long: 'UTC' },
'Europe/London': { short: 'GMT', long: 'Edinburgh, London' },
'Europe/Dublin': { short: 'GMT', long: 'Dublin' },
'Europe/Lisbon': { short: 'WET', long: 'Lisbon' },
'Africa/Casablanca': { short: 'WET', long: 'Casablanca, Monrovia' },
'Atlantic/Canary': { short: 'WET', long: 'Canary Islands' },
'Europe/Belgrade': {
short: 'CET',
long: 'Belgrade, Bratislava, Budapest, Ljubljana, Prague'
},
'Europe/Sarajevo': { short: 'CET', long: 'Sarajevo, Skopje, Warsaw, Zagreb' },
'Europe/Brussels': {
short: 'CET',
long: 'Brussels, Copenhagen, Madrid, Paris'
},
'Europe/Amsterdam': {
short: 'CET',
long: 'Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna'
},
'Africa/Algiers': { short: 'CET', long: 'West Central Africa' },
'Europe/Bucharest': { short: 'EET', long: 'Bucharest' },
'Africa/Cairo': { short: 'EET', long: 'Cairo' },
'Europe/Helsinki': {
short: 'EET',
long: 'Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius'
},
'Europe/Athens': { short: 'EET', long: 'Athens, Istanbul, Minsk' },
'Asia/Jerusalem': { short: 'IST', long: 'Jerusalem' },
'Africa/Harare': { short: 'CAT', long: 'Harare, Pretoria' },
'Europe/Moscow': { short: 'MSK', long: 'Moscow, St. Petersburg, Volgograd' },
'Asia/Kuwait': { short: 'AST', long: 'Kuwait, Riyadh' },
'Africa/Nairobi': { short: 'EAT', long: 'Nairobi' },
'Asia/Baghdad': { short: 'AST', long: 'Baghdad' },
'Asia/Tehran': { short: 'IRST', long: 'Tehran' },
'Asia/Dubai': { short: 'GST', long: 'Abu Dhabi, Muscat' },
'Asia/Baku': { short: 'AZT', long: 'Baku, Tbilisi, Yerevan' },
'Asia/Kabul': { short: 'AFT', long: 'Kabul' },
'Asia/Yekaterinburg': { short: 'YEKT', long: 'Ekaterinburg' },
'Asia/Karachi': { short: 'PKT', long: 'Islamabad, Karachi, Tashkent' },
'Asia/Kolkata': { short: 'IST', long: 'Chennai, Kolkata, Mumbai, New Delhi' },
'Asia/Kathmandu': { short: null, long: 'Kathmandu' },
'Asia/Dhaka': { short: 'BST', long: 'Astana, Dhaka' },
'Asia/Colombo': { short: 'IST', long: 'Sri Jayawardenepura' },
'Asia/Almaty': { short: 'ALMT', long: 'Almaty, Novosibirsk' },
'Asia/Rangoon': { short: null, long: 'Yangon Rangoon' },
'Asia/Bangkok': { short: 'ICT', long: 'Bangkok, Hanoi, Jakarta' },
'Asia/Krasnoyarsk': { short: 'KRAT', long: 'Krasnoyarsk' },
'Asia/Shanghai': {
short: 'CST',
long: 'Beijing, Chongqing, Hong Kong SAR, Urumqi'
},
'Asia/Kuala_Lumpur': { short: 'MYT', long: 'Kuala Lumpur, Singapore' },
'Asia/Taipei': { short: 'CST', long: 'Taipei' },
'Australia/Perth': { short: 'AWST', long: 'Perth' },
'Asia/Irkutsk': { short: 'IRKT', long: 'Irkutsk, Ulaanbaatar' },
'Asia/Seoul': { short: 'KST', long: 'Seoul' },
'Asia/Tokyo': { short: 'JST', long: 'Osaka, Sapporo, Tokyo' },
'Asia/Yakutsk': { short: 'YAKT', long: 'Yakutsk' },
'Australia/Darwin': { short: 'ACST', long: 'Darwin' },
'Australia/Adelaide': { short: 'ACDT', long: 'Adelaide' },
'Australia/Sydney': { short: 'AEDT', long: 'Canberra, Melbourne, Sydney' },
'Australia/Brisbane': { short: 'AEST', long: 'Brisbane' },
'Australia/Hobart': { short: 'AEDT', long: 'Hobart' },
'Asia/Vladivostok': { short: 'VLAT', long: 'Vladivostok' },
'Pacific/Guam': { short: 'ChST', long: 'Guam, Port Moresby' },
'Asia/Magadan': {
short: 'MAGT',
long: 'Magadan, Solomon Islands, New Caledonia'
},
'Asia/Kamchatka': { short: 'PETT', long: 'Kamchatka, Marshall Islands' },
'Pacific/Fiji': { short: 'FJT', long: 'Fiji Islands' },
'Pacific/Auckland': { short: 'NZDT', long: 'Auckland, Wellington' },
'Pacific/Tongatapu': { short: null, long: "Nuku'alofa" }
}
const buildTzLabels = timezoneList => {
@ -106,7 +130,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 +141,6 @@ const buildTzLabels = timezoneList => {
)
}
export default buildTzLabels(timezones)
const labels = buildTzLabels(timezones)
export { labels, timezones }