partial: Analytics css migration

This commit is contained in:
Rafael Taranto 2025-04-28 10:06:33 +01:00
parent b9b7dcdcd7
commit 92ccd8cb92
12 changed files with 116 additions and 268 deletions

View file

@ -1,6 +1,4 @@
import { useQuery, gql } from "@apollo/client"; import { useQuery, gql } from '@apollo/client'
import Box from '@mui/material/Box'
import { makeStyles } from '@mui/styles'
import classnames from 'classnames' import classnames from 'classnames'
import { endOfToday } from 'date-fns' import { endOfToday } from 'date-fns'
import { subDays, format, add, startOfWeek } from 'date-fns/fp' import { subDays, format, add, startOfWeek } from 'date-fns/fp'
@ -17,15 +15,12 @@ import { fromNamespace } from 'src/utils/config'
import { numberToFiatAmount } from 'src/utils/number' import { numberToFiatAmount } from 'src/utils/number'
import { DAY, WEEK, MONTH } from 'src/utils/time' import { DAY, WEEK, MONTH } from 'src/utils/time'
import styles from './Analytics.styles'
import LegendEntry from './components/LegendEntry' import LegendEntry from './components/LegendEntry'
import HourOfDayWrapper from './components/wrappers/HourOfDayWrapper' import HourOfDayWrapper from './components/wrappers/HourOfDayWrapper'
import OverTimeWrapper from './components/wrappers/OverTimeWrapper' import OverTimeWrapper from './components/wrappers/OverTimeWrapper'
import TopMachinesWrapper from './components/wrappers/TopMachinesWrapper' import TopMachinesWrapper from './components/wrappers/TopMachinesWrapper'
import VolumeOverTimeWrapper from './components/wrappers/VolumeOverTimeWrapper' import VolumeOverTimeWrapper from './components/wrappers/VolumeOverTimeWrapper'
const useStyles = makeStyles(styles)
const MACHINE_OPTIONS = [{ code: 'all', display: 'All machines' }] const MACHINE_OPTIONS = [{ code: 'all', display: 'All machines' }]
const REPRESENTING_OPTIONS = [ const REPRESENTING_OPTIONS = [
{ code: 'overTime', display: 'Over time' }, { code: 'overTime', display: 'Over time' },
@ -106,26 +101,28 @@ const GET_DATA = gql`
} }
` `
const OverviewEntry = ({ label, value, oldValue, currency }) => { const VerticalLine = () => (
const classes = useStyles() <div className="h-16 border-solid border border-comet2" />
)
const OverviewEntry = ({ label, value, oldValue, currency }) => {
const _oldValue = !oldValue || R.equals(oldValue, 0) ? 1 : oldValue const _oldValue = !oldValue || R.equals(oldValue, 0) ? 1 : oldValue
const growthRate = ((value - oldValue) * 100) / _oldValue const growthRate = ((value - oldValue) * 100) / _oldValue
const growthClasses = { const growthClasses = {
[classes.growthPercentage]: true, 'font-bold': true,
[classes.growth]: R.gt(value, oldValue), 'text-malachite': R.gt(value, oldValue),
[classes.decline]: R.gt(oldValue, value) 'text-tomato': R.gt(oldValue, value)
} }
return ( return (
<div className={classes.overviewEntry}> <div>
<P noMargin>{label}</P> <P noMargin>{label}</P>
<Info2 noMargin className={classes.overviewFieldWrapper}> <Info2 noMargin className="mt-[6px] mb-[6px]">
<span>{numberToFiatAmount(value)}</span> <span className="text-[24px]">{numberToFiatAmount(value)}</span>
{!!currency && ` ${currency}`} {!!currency && ` ${currency}`}
</Info2> </Info2>
<span className={classes.overviewGrowth}> <span className="flex items-center gap-1">
{R.gt(growthRate, 0) && <UpIcon height={10} />} {R.gt(growthRate, 0) && <UpIcon height={10} />}
{R.lt(growthRate, 0) && <DownIcon height={10} />} {R.lt(growthRate, 0) && <DownIcon height={10} />}
{R.equals(growthRate, 0) && <EqualIcon height={10} />} {R.equals(growthRate, 0) && <EqualIcon height={10} />}
@ -138,8 +135,6 @@ const OverviewEntry = ({ label, value, oldValue, currency }) => {
} }
const Analytics = () => { const Analytics = () => {
const classes = useStyles()
const { data: txResponse, loading: txLoading } = useQuery(GET_TRANSACTIONS, { const { data: txResponse, loading: txLoading } = useQuery(GET_TRANSACTIONS, {
variables: { variables: {
from: subDays(65, endOfToday()), from: subDays(65, endOfToday()),
@ -320,7 +315,7 @@ const Analytics = () => {
!loading && ( !loading && (
<> <>
<TitleSection title="Analytics"> <TitleSection title="Analytics">
<Box className={classes.overviewLegend}> <div className="flex gap-6 justify-end">
<LegendEntry <LegendEntry
IconComponent={UpIcon} IconComponent={UpIcon}
label={'Up since last period'} label={'Up since last period'}
@ -333,10 +328,10 @@ const Analytics = () => {
IconComponent={EqualIcon} IconComponent={EqualIcon}
label={'Same since last period'} label={'Same since last period'}
/> />
</Box> </div>
</TitleSection> </TitleSection>
<div className={classes.dropdownsOverviewWrapper}> <div className="flex justify-between items-center mb-4">
<div className={classes.dropdowns}> <div className="flex flex-row gap-6">
<Select <Select
label="Representing" label="Representing"
onSelectedItemChange={handleRepresentationChange} onSelectedItemChange={handleRepresentationChange}
@ -354,27 +349,27 @@ const Analytics = () => {
defaultAsFilter defaultAsFilter
/> />
</div> </div>
<div className={classes.overview}> <div className="flex flex-row items-center gap-10">
<OverviewEntry <OverviewEntry
label="Transactions" label="Transactions"
value={txs.current} value={txs.current}
oldValue={txs.previous} oldValue={txs.previous}
/> />
<div className={classes.verticalLine} /> <VerticalLine />
<OverviewEntry <OverviewEntry
label="Median amount" label="Median amount"
value={medianAmount.current} value={medianAmount.current}
oldValue={medianAmount.previous} oldValue={medianAmount.previous}
currency={fiatLocale} currency={fiatLocale}
/> />
<div className={classes.verticalLine} /> <VerticalLine />
<OverviewEntry <OverviewEntry
label="Volume" label="Volume"
value={txVolume.current} value={txVolume.current}
oldValue={txVolume.previous} oldValue={txVolume.previous}
currency={fiatLocale} currency={fiatLocale}
/> />
<div className={classes.verticalLine} /> <VerticalLine />
<OverviewEntry <OverviewEntry
label="Commissions" label="Commissions"
value={commissions.current} value={commissions.current}

View file

@ -1,163 +0,0 @@
import {
offColor,
offDarkColor,
tomato,
neon,
java
} from 'src/styling/variables'
import typographyStyles from '../../components/typography/styles'
const { label1 } = typographyStyles
const styles = {
overviewLegend: {
display: 'flex',
justifyContent: 'flex-end',
'& span': {
marginRight: 24
},
'& > :last-child': {
marginRight: 0
}
},
legendEntry: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
'& > :first-child': {
marginRight: 8
}
},
dropdownsOverviewWrapper: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16
},
verticalLine: {
height: 64,
width: 1,
border: 'solid',
borderWidth: 0.5,
borderColor: offDarkColor
},
dropdowns: {
display: 'flex',
flexDirection: 'row',
'& div': {
marginRight: 24
},
'& > :last-child': {
marginRight: 0
}
},
overview: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
'& div': {
marginRight: 40
},
'& > :last-child': {
marginRight: 0
}
},
overviewFieldWrapper: {
marginTop: 6,
marginBottom: 6,
'& span': {
fontSize: 24
}
},
overviewGrowth: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
'& p': {
marginLeft: 4
}
},
growthPercentage: {
fontWeight: 'bold'
},
growth: {
color: '#00CD5A'
},
decline: {
color: tomato
},
// Graph
graphHeaderWrapper: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 40
},
graphHeaderLeft: {
display: 'flex',
flexDirection: 'column'
},
graphHeaderRight: {
marginTop: 15,
display: 'flex',
flexDirection: 'row',
'& > *': {
marginRight: 30,
'&:last-child': {
marginRight: 0
}
}
},
graphLegend: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
'& span': {
marginRight: 24
},
'& > :last-child': {
marginRight: 0
}
},
machineSelector: {
width: 248
},
cashInIcon: {
width: 12,
height: 12,
borderRadius: 12,
backgroundColor: java
},
cashOutIcon: {
width: 12,
height: 12,
borderRadius: 12,
backgroundColor: neon
},
txIcon: {
width: 12,
height: 12,
borderRadius: 12,
backgroundColor: '#000'
},
topMachinesRadio: {
display: 'flex',
flexDirection: 'row'
},
graphHeaderSwitchBox: {
display: 'flex',
flexDirection: 'column',
'& > *': {
margin: 0
},
'& > :first-child': {
marginBottom: 2,
extend: label1,
color: offColor
}
}
}
export default styles

View file

@ -1,16 +1,9 @@
import { makeStyles } from '@mui/styles'
import React from 'react' import React from 'react'
import { P } from 'src/components/typography' import { P } from 'src/components/typography'
import styles from '../Analytics.styles'
const useStyles = makeStyles(styles)
const LegendEntry = ({ IconElement, IconComponent, label }) => { const LegendEntry = ({ IconElement, IconComponent, label }) => {
const classes = useStyles()
return ( return (
<span className={classes.legendEntry}> <span className="flex items-center gap-2">
{!!IconComponent && <IconComponent height={12} />} {!!IconComponent && <IconComponent height={12} />}
{!!IconElement && IconElement} {!!IconElement && IconElement}
<P>{label}</P> <P>{label}</P>

View file

@ -10,10 +10,6 @@ import { numberToFiatAmount } from 'src/utils/number'
import { singularOrPlural } from 'src/utils/string' import { singularOrPlural } from 'src/utils/string'
import { formatDate, formatDateNonUtc } from 'src/utils/timezones' import { formatDate, formatDateNonUtc } from 'src/utils/timezones'
import styles from './GraphTooltip.styles'
const useStyles = makeStyles(styles)
const GraphTooltip = ({ const GraphTooltip = ({
coords, coords,
data, data,
@ -22,8 +18,6 @@ const GraphTooltip = ({
currency, currency,
representing representing
}) => { }) => {
const classes = useStyles(coords)
const formattedDateInterval = !R.includes('hourOfDay', representing.code) const formattedDateInterval = !R.includes('hourOfDay', representing.code)
? [ ? [
formatDate(dateInterval[1], null, 'MMM d'), formatDate(dateInterval[1], null, 'MMM d'),
@ -48,28 +42,30 @@ const GraphTooltip = ({
) )
return ( return (
<Paper className={classes.dotOtWrapper}> <Paper
className="absolute top-[351px] w-[150px] p-3 rounded-lg"
style={{ left: coords?.x ?? 0 }}>
{!R.includes('hourOfDay', representing.code) && ( {!R.includes('hourOfDay', representing.code) && (
<Info2 noMargin>{`${formattedDateInterval[0]}`}</Info2> <Info2 noMargin>{`${formattedDateInterval[0]}`}</Info2>
)} )}
<Info2 noMargin> <Info2 noMargin>
{`${formattedDateInterval[1]} - ${formattedDateInterval[2]}`} {`${formattedDateInterval[1]} - ${formattedDateInterval[2]}`}
</Info2> </Info2>
<P noMargin className={classes.dotOtTransactionAmount}> <P noMargin className="my-2">
{R.length(data)}{' '} {R.length(data)}{' '}
{singularOrPlural(R.length(data), 'transaction', 'transactions')} {singularOrPlural(R.length(data), 'transaction', 'transactions')}
</P> </P>
<P noMargin className={classes.dotOtTransactionVolume}> <P noMargin className="text-comet">
{numberToFiatAmount(transactions.volume)} {currency} in volume {numberToFiatAmount(transactions.volume)} {currency} in volume
</P> </P>
<div className={classes.dotOtTransactionClasses}> <div className="mt-4">
<Label3 noMargin> <Label3 noMargin>
<TxInIcon /> <TxInIcon />
<span>{transactions.cashIn} cash-in</span> <span className="ml-1">{transactions.cashIn} cash-in</span>
</Label3> </Label3>
<Label3 noMargin> <Label3 noMargin className="mt-1">
<TxOutIcon /> <TxOutIcon />
<span>{transactions.cashOut} cash-out</span> <span className="ml-1">{transactions.cashOut} cash-out</span>
</Label3> </Label3>
</div> </div>
</Paper> </Paper>

View file

@ -1,29 +0,0 @@
import { comet } from 'src/styling/variables'
const styles = {
dotOtWrapper: {
position: 'absolute',
top: coords => coords?.y ?? 0,
left: coords => coords?.x ?? 0,
width: 150,
padding: 12,
borderRadius: 8
},
dotOtTransactionAmount: {
margin: [[8, 0, 8, 0]]
},
dotOtTransactionVolume: {
color: comet
},
dotOtTransactionClasses: {
marginTop: 15,
'& p > span': {
marginLeft: 5
},
'& p:last-child': {
marginTop: 5
}
}
}
export default styles

View file

@ -1,5 +1,4 @@
import Box from '@mui/material/Box' import Box from '@mui/material/Box'
import { makeStyles } from '@mui/styles'
import { getTimezoneOffset } from 'date-fns-tz' import { getTimezoneOffset } from 'date-fns-tz'
import * as R from 'ramda' import * as R from 'ramda'
import React, { useState } from 'react' import React, { useState } from 'react'
@ -8,11 +7,9 @@ import { H2 } from 'src/components/typography'
import { Select } from 'src/components/inputs' import { Select } from 'src/components/inputs'
import { MINUTE } from 'src/utils/time' import { MINUTE } from 'src/utils/time'
import styles from '../../Analytics.styles'
import Graph from '../../graphs/Graph' import Graph from '../../graphs/Graph'
import LegendEntry from '../LegendEntry' import LegendEntry from '../LegendEntry'
import classes from './wrappers.module.css'
const useStyles = makeStyles(styles)
const options = [ const options = [
{ code: 'hourOfDayTransactions', display: 'Transactions' }, { code: 'hourOfDayTransactions', display: 'Transactions' },
@ -32,8 +29,6 @@ const HourOfDayBarGraphHeader = ({
timezone, timezone,
currency currency
}) => { }) => {
const classes = useStyles()
const [graphType /*, setGraphType */] = useState(options[0].code) const [graphType /*, setGraphType */] = useState(options[0].code)
const legend = { const legend = {

View file

@ -1,17 +1,14 @@
import Switch from '@mui/material/Switch' import Switch from '@mui/material/Switch'
import Box from '@mui/material/Box' import Box from '@mui/material/Box'
import { makeStyles } from '@mui/styles'
import React, { useState } from 'react' import React, { useState } from 'react'
import { H2 } from 'src/components/typography' import { H2, Label1 } from 'src/components/typography'
import { Select } from 'src/components/inputs' import { Select } from 'src/components/inputs'
import { primaryColor } from 'src/styling/variables' import { primaryColor } from 'src/styling/variables'
import styles from '../../Analytics.styles'
import Graph from '../../graphs/Graph' import Graph from '../../graphs/Graph'
import LegendEntry from '../LegendEntry' import LegendEntry from '../LegendEntry'
import classes from './wrappers.module.css'
const useStyles = makeStyles(styles)
const OverTimeDotGraphHeader = ({ const OverTimeDotGraphHeader = ({
title, title,
@ -24,8 +21,6 @@ const OverTimeDotGraphHeader = ({
timezone, timezone,
currency currency
}) => { }) => {
const classes = useStyles()
const [logarithmic, setLogarithmic] = useState() const [logarithmic, setLogarithmic] = useState()
const legend = { const legend = {
@ -61,8 +56,13 @@ const OverTimeDotGraphHeader = ({
</div> </div>
<div className={classes.graphHeaderRight}> <div className={classes.graphHeaderRight}>
<div className={classes.graphHeaderSwitchBox}> <div className={classes.graphHeaderSwitchBox}>
<span>Log. scale</span> <Label1 noMargin className="mb-1 text-comet">
<Switch onChange={event => setLogarithmic(event.target.checked)} /> Log. scale
</Label1>
<Switch
className="m-0"
onChange={event => setLogarithmic(event.target.checked)}
/>
</div> </div>
<Select <Select
label="Machines" label="Machines"

View file

@ -1,14 +1,11 @@
import Box from '@mui/material/Box' import Box from '@mui/material/Box'
import { makeStyles } from '@mui/styles'
import * as R from 'ramda' import * as R from 'ramda'
import React, { useState } from 'react' import React, { useState } from 'react'
import { H2 } from 'src/components/typography' import { H2 } from 'src/components/typography'
import styles from '../../Analytics.styles'
import Graph from '../../graphs/Graph' import Graph from '../../graphs/Graph'
import LegendEntry from '../LegendEntry' import LegendEntry from '../LegendEntry'
import classes from './wrappers.module.css'
const useStyles = makeStyles(styles)
const options = [ const options = [
{ code: 'topMachinesTransactions', display: 'Transactions' }, { code: 'topMachinesTransactions', display: 'Transactions' },
@ -24,8 +21,6 @@ const TopMachinesBarGraphHeader = ({
timezone, timezone,
currency currency
}) => { }) => {
const classes = useStyles()
const [graphType /*, setGraphType */] = useState(options[0].code) const [graphType /*, setGraphType */] = useState(options[0].code)
const legend = { const legend = {

View file

@ -1,17 +1,14 @@
import Box from '@mui/material/Box' import Box from '@mui/material/Box'
import Switch from '@mui/material/Switch' import Switch from '@mui/material/Switch'
import { makeStyles } from '@mui/styles'
import React, { useState } from 'react' import React, { useState } from 'react'
import { H2 } from 'src/components/typography' import { H2, Label1 } from 'src/components/typography'
import { Select } from 'src/components/inputs' import { Select } from 'src/components/inputs'
import { neon, java } from 'src/styling/variables' import { neon, java } from 'src/styling/variables'
import styles from '../../Analytics.styles'
import Graph from '../../graphs/Graph' import Graph from '../../graphs/Graph'
import LegendEntry from '../LegendEntry' import LegendEntry from '../LegendEntry'
import classes from './wrappers.module.css'
const useStyles = makeStyles(styles)
const VolumeOverTimeGraphHeader = ({ const VolumeOverTimeGraphHeader = ({
title, title,
@ -24,8 +21,6 @@ const VolumeOverTimeGraphHeader = ({
timezone, timezone,
currency currency
}) => { }) => {
const classes = useStyles()
const [logarithmic, setLogarithmic] = useState() const [logarithmic, setLogarithmic] = useState()
const legend = { const legend = {
@ -63,8 +58,13 @@ const VolumeOverTimeGraphHeader = ({
</div> </div>
<div className={classes.graphHeaderRight}> <div className={classes.graphHeaderRight}>
<div className={classes.graphHeaderSwitchBox}> <div className={classes.graphHeaderSwitchBox}>
<span>Log. scale</span> <Label1 noMargin className="mb-1 text-comet">
<Switch onChange={event => setLogarithmic(event.target.checked)} /> Log. scale
</Label1>
<Switch
className="m-0"
onChange={event => setLogarithmic(event.target.checked)}
/>
</div> </div>
<Select <Select
label="Machines" label="Machines"

View file

@ -0,0 +1,56 @@
.graphHeaderWrapper {
display: flex;
justify-content: space-between;
margin-bottom: 40px;
}
.graphHeaderLeft {
display: flex;
flex-direction: column;
}
.graphHeaderRight {
margin-top: 15px;
display: flex;
gap: 30px
}
.cashInIcon {
width: 12px;
height: 12px;
border-radius: 12px;
background-color: var(--java);
}
.cashOutIcon {
width: 12px;
height: 12px;
border-radius: 12px;
background-color: var(--neon);
}
.graphLegend {
display: flex;
align-items: center;
gap: 24px;
}
.txIcon {
width: 12px;
height: 12px;
border-radius: 12px;
background-color: #000;
}
.graphHeaderSwitchBox {
display: flex;
flex-direction: column;
/*'& > *': {*/
/* margin: 0*/
/*},*/
/*'& > :first-child': {*/
/* marginBottom: 2,*/
/* extend: label1,*/
/* color: offColor*/
/*}*/
}

View file

@ -13,10 +13,17 @@
--spring3: #ecfbef; --spring3: #ecfbef;
--comet: #5f668a; --comet: #5f668a;
--comet2: #72799d;
--comet3: #525772;
--tomato: #ff584a; --tomato: #ff584a;
--ghost: #fafbff; --ghost: #fafbff;
--zircon: #ebefff; --zircon: #ebefff;
--java: #16d6d3;
--neon: #5a67ff;
--malachite: #00CD5A;
} }
@theme { @theme {
@ -25,9 +32,12 @@
--color-spring2: var(--spring2); --color-spring2: var(--spring2);
--color-spring3: var(--spring3); --color-spring3: var(--spring3);
--color-comet: var(--comet); --color-comet: var(--comet);
--color-comet2: var(--comet2);
--color-comet3: var(--comet3);
--color-tomato: var(--tomato); --color-tomato: var(--tomato);
--color-ghost: var(--ghost); --color-ghost: var(--ghost);
--color-zircon: var(--zircon); --color-zircon: var(--zircon);
--color-malachite: var(--malachite);
} }
body { body {