Merge branch 'Create-Dashboard' of https://github.com/nimbus-gui/nimbus-gui into Create-Dashboard
This commit is contained in:
commit
8922170358
Binary file not shown.
After Width: | Height: | Size: 107 KiB |
|
@ -15,3 +15,20 @@ export const BAD_NETWORK_TEXT = 'Network Latency is high.'
|
|||
export const KEYSTORE_FILES = 'KeystoreFiles'
|
||||
export const RECOVERY_PHRASE = 'Recovery Phrase'
|
||||
export const BOTH_KEY_AND_RECOVERY = 'Both KeystoreFiles & Recovery Phrase'
|
||||
|
||||
/* Dashboard */
|
||||
|
||||
export const years = [
|
||||
'JAN',
|
||||
'FEB',
|
||||
'MAR',
|
||||
'APR',
|
||||
'MAY',
|
||||
'JUN',
|
||||
'JUL',
|
||||
'AUG',
|
||||
'SEPT',
|
||||
'OCT',
|
||||
'NOV',
|
||||
'DEC',
|
||||
]
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import BalanceChartCard from './BalanceChartCard'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/BalanceChartCard',
|
||||
component: BalanceChartCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof BalanceChartCard>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
import { useState } from 'react'
|
||||
import { Stack, XStack, YStack } from 'tamagui'
|
||||
import { Calendar } from '@status-im/components'
|
||||
import { Text } from '@status-im/components'
|
||||
import { DateRange } from 'react-day-picker'
|
||||
|
||||
import DashboardCardWrapper from '../DashboardCardWrapper'
|
||||
import LineChart from './LineChart'
|
||||
import Icon from '../../../components/General/Icon'
|
||||
import { years } from '../../../constants'
|
||||
import './calendar.css'
|
||||
|
||||
const userGains = [
|
||||
10000, 15000, 17500, 20000, 19000, 23222, 25000, 20000, 20000, 21000, 22300, 21000,
|
||||
]
|
||||
|
||||
const getMonthIndicesFromRange = (range: DateRange) => {
|
||||
if (!range.from || !range.to) return [0, 11]
|
||||
|
||||
return [range.from.getMonth(), range.to.getMonth()]
|
||||
}
|
||||
|
||||
const BalanceChartCard = () => {
|
||||
const [isCalendarVisible, setIsCalendarVisible] = useState(false)
|
||||
const [dateRange, setDateRange] = useState<DateRange>({ from: undefined, to: undefined })
|
||||
const [startMonth, endMonth] = getMonthIndicesFromRange(dateRange)
|
||||
const filteredYears = years.slice(startMonth, endMonth + 1)
|
||||
const filteredUserGains = userGains.slice(startMonth, endMonth + 1)
|
||||
|
||||
const handleRangeSelect = (
|
||||
range: DateRange | undefined,
|
||||
// @NOTE: You can take selectedDay: Date,
|
||||
) => {
|
||||
if (!range) {
|
||||
setDateRange({ from: undefined, to: undefined })
|
||||
return
|
||||
}
|
||||
setDateRange(range)
|
||||
if (range.from && range.to) {
|
||||
setIsCalendarVisible(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<DashboardCardWrapper>
|
||||
<Stack style={{ width: '536px' }}>
|
||||
<YStack space={'$4'}>
|
||||
<XStack justifyContent={'space-between'}>
|
||||
<YStack>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
Balance
|
||||
</Text>
|
||||
<XStack
|
||||
style={{ alignItems: 'end' }}
|
||||
space={'$1'}
|
||||
onClick={() => setIsCalendarVisible(true)}
|
||||
>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
24,273
|
||||
</Text>
|
||||
<Text size={11} color="#23ADA0">
|
||||
1.56%
|
||||
</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
<XStack
|
||||
onClick={() => setIsCalendarVisible(prev => !prev)}
|
||||
style={{
|
||||
border: '2px solid #09101C14',
|
||||
height: 'fit-content',
|
||||
padding: '3px',
|
||||
borderRadius: '10px',
|
||||
}}
|
||||
>
|
||||
<Text size={13} weight={'semibold'}>
|
||||
{dateRange?.from ? dateRange.from.toLocaleDateString() + ' ->' : 'Start Date -> '}{' '}
|
||||
</Text>
|
||||
<Text size={13} weight={'semibold'}>
|
||||
{dateRange?.to ? dateRange.to.toLocaleDateString() : ' End Date'}
|
||||
</Text>
|
||||
<Icon src="/icons/edit.svg" />
|
||||
</XStack>
|
||||
</XStack>
|
||||
{isCalendarVisible && (
|
||||
<Calendar
|
||||
style={{
|
||||
backgroundColor: 'white',
|
||||
position: 'absolute',
|
||||
zIndex: 1000,
|
||||
top: '100%',
|
||||
right: '0',
|
||||
}}
|
||||
mode="range"
|
||||
selected={dateRange}
|
||||
onSelect={handleRangeSelect}
|
||||
/>
|
||||
)}
|
||||
<LineChart years={filteredYears} userGains={filteredUserGains} />
|
||||
</YStack>
|
||||
</Stack>
|
||||
</DashboardCardWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default BalanceChartCard
|
|
@ -0,0 +1,32 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import { Stack } from 'tamagui'
|
||||
|
||||
import LineChart from './LineChart'
|
||||
import { years } from '../../../constants'
|
||||
|
||||
const userGains = [
|
||||
10000, 15000, 17500, 20000, 19000, 23222, 25000, 20000, 20000, 21000, 22300, 21000,
|
||||
]
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/LineChart',
|
||||
component: LineChart,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
decorators: [
|
||||
StoryObj => (
|
||||
<Stack width={'536px'}>
|
||||
<StoryObj />,
|
||||
</Stack>
|
||||
),
|
||||
],
|
||||
} satisfies Meta<typeof LineChart>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: { userGains, years },
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Filler,
|
||||
} from 'chart.js'
|
||||
import { Line } from 'react-chartjs-2'
|
||||
|
||||
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Filler)
|
||||
|
||||
type LineChartProps = {
|
||||
years: string[]
|
||||
userGains: number[]
|
||||
}
|
||||
|
||||
const LineChart = ({ years, userGains }: LineChartProps) => {
|
||||
const data = {
|
||||
type: 'line',
|
||||
labels: years,
|
||||
datasets: [
|
||||
{
|
||||
data: userGains,
|
||||
borderColor: '#1992D7',
|
||||
backgroundColor: '#f6fbfd',
|
||||
fill: true,
|
||||
tension: 0.4,
|
||||
pointRadius: 0,
|
||||
},
|
||||
],
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
},
|
||||
}
|
||||
|
||||
return <Line options={data.options} data={data} />
|
||||
}
|
||||
|
||||
export default LineChart
|
|
@ -1,73 +0,0 @@
|
|||
import './calendar.css'
|
||||
import { Stack, XStack, YStack } from "tamagui";
|
||||
import DashboardCardWrapper from "../DashboardCardWrapper";
|
||||
import { Text } from "@status-im/components";
|
||||
import LineChart from "./LineChart";
|
||||
import Icon from "../../../components/General/Icon";
|
||||
import { DateRange } from 'react-day-picker';
|
||||
import { Calendar } from '@status-im/components'
|
||||
import { useState } from "react";
|
||||
|
||||
|
||||
const years = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEPT', 'OCT', 'NOV', 'DEC']
|
||||
const userGains = [10000, 15000, 17500, 20000, 19000, 23222, 25000, 20000, 20000, 21000, 22300, 21000]
|
||||
|
||||
const getMonthIndicesFromRange = (range: DateRange) => {
|
||||
if (!range.from || !range.to) return [0, 11];
|
||||
|
||||
return [range.from.getMonth(), range.to.getMonth()];
|
||||
};
|
||||
const BalanceChardCard = () => {
|
||||
const [isCalendarVisible, setIsCalendarVisible] = useState(false)
|
||||
const [dateRange, setDateRange] = useState<DateRange>({ from: undefined, to: undefined });
|
||||
const [startMonth, endMonth] = getMonthIndicesFromRange(dateRange);
|
||||
const filteredYears = years.slice(startMonth, endMonth + 1);
|
||||
const filteredUserGains = userGains.slice(startMonth, endMonth + 1);
|
||||
|
||||
const handleRangeSelect = (
|
||||
range: DateRange | undefined,
|
||||
// @NOTE: You can take selectedDay: Date,
|
||||
) => {
|
||||
if (!range) {
|
||||
setDateRange({ from: undefined, to: undefined });
|
||||
return;
|
||||
}
|
||||
setDateRange(range);
|
||||
if (range.from && range.to) {
|
||||
setIsCalendarVisible(false)
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardCardWrapper >
|
||||
<Stack style={{ width: '536px' }}>
|
||||
<YStack space={'$4'}>
|
||||
<XStack justifyContent={'space-between'}>
|
||||
<YStack>
|
||||
<Text size={15} weight={'semibold'}> Balance</Text>
|
||||
<XStack style={{ alignItems: 'end', }} space={'$1'} onClick={() => setIsCalendarVisible(true)}>
|
||||
<Text size={27} weight={'semibold'}>24,273</Text>
|
||||
<Text size={11} color="#23ADA0" >1.56%</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
<XStack onClick={() => setIsCalendarVisible((prev) => !prev)} style={{ border: '2px solid #09101C14', height: 'fit-content', padding: '3px', borderRadius: '10px' }}>
|
||||
<Text size={13} weight={'semibold'}>{dateRange?.from ? dateRange.from.toLocaleDateString() + ' ->' : 'Start Date -> '} </Text>
|
||||
<Text size={13} weight={'semibold'}>{dateRange?.to ? dateRange.to.toLocaleDateString() : ' End Date'}</Text>
|
||||
<Icon src="/icons/edit.svg" />
|
||||
</XStack>
|
||||
</XStack>
|
||||
{isCalendarVisible && (
|
||||
<Calendar
|
||||
style={{ backgroundColor: 'white', position: 'absolute', zIndex: 1000, top: '100%', right: '0' }}
|
||||
mode="range"
|
||||
selected={dateRange}
|
||||
onSelect={handleRangeSelect}
|
||||
/>
|
||||
)}
|
||||
<LineChart years={filteredYears} userGains={filteredUserGains} />
|
||||
</YStack>
|
||||
</Stack>
|
||||
</DashboardCardWrapper>
|
||||
)
|
||||
}
|
||||
export default BalanceChardCard;
|
|
@ -1,29 +0,0 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import LineChart from './LineChart'
|
||||
import { Stack } from 'tamagui'
|
||||
|
||||
const years = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEPT', 'OCT', 'NOV', 'DEC']
|
||||
const userGains = [10000, 15000, 17500, 20000, 19000, 23222, 25000, 20000, 20000, 21000, 22300, 21000]
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/LineChart',
|
||||
component: LineChart,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
decorators: [StoryObj =>
|
||||
(
|
||||
<Stack width={'536px'}>
|
||||
<StoryObj />,
|
||||
</Stack>
|
||||
)
|
||||
]
|
||||
} satisfies Meta<typeof LineChart>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Page: Story = {
|
||||
args: { userGains, years },
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Filler,
|
||||
} from 'chart.js';
|
||||
import { Line } from 'react-chartjs-2';
|
||||
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Filler,
|
||||
);
|
||||
|
||||
|
||||
|
||||
type LineChartProps = {
|
||||
years: string[];
|
||||
userGains: number[];
|
||||
};
|
||||
const LineChart = ({ years, userGains }: LineChartProps) => {
|
||||
const data = {
|
||||
type: 'line',
|
||||
labels: years,
|
||||
datasets: [
|
||||
{
|
||||
data: userGains,
|
||||
borderColor: '#1992D7',
|
||||
backgroundColor: '#f6fbfd',
|
||||
fill: true,
|
||||
tension: 0.4,
|
||||
pointRadius: 0,
|
||||
}
|
||||
],
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
}
|
||||
|
||||
};
|
||||
return <Line options={data.options} data={data} />;
|
||||
}
|
||||
|
||||
export default LineChart;
|
|
@ -14,6 +14,6 @@ const meta = {
|
|||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Page: Story = {
|
||||
args: {load:[32,12,45,10]},
|
||||
export const Default: Story = {
|
||||
args: { load: [32, 12, 45, 10] },
|
||||
}
|
||||
|
|
|
@ -1,88 +1,96 @@
|
|||
import StandartLineChart from '../../../components/Charts/StandardLineChart'
|
||||
import IconText from '../../../components/General/IconText'
|
||||
import { Paragraph, Separator, XStack, YStack } from 'tamagui'
|
||||
import { Shadow, Text } from '@status-im/components'
|
||||
import { IncorrectIcon } from '@status-im/icons'
|
||||
|
||||
import StandartLineChart from '../../../components/Charts/StandardLineChart'
|
||||
import IconText from '../../../components/General/IconText'
|
||||
import Icon from '../../../components/General/Icon'
|
||||
|
||||
type DataPoint = {
|
||||
x: number
|
||||
y: number
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
type ChartData = {
|
||||
id: string
|
||||
color: string
|
||||
data: DataPoint[]
|
||||
id: string
|
||||
color: string
|
||||
data: DataPoint[]
|
||||
}
|
||||
|
||||
type CPUCardProps = {
|
||||
load: number[]
|
||||
load: number[]
|
||||
}
|
||||
|
||||
const CPUCard = ({ load }: CPUCardProps) => {
|
||||
const chartData: ChartData[] = [
|
||||
{
|
||||
id: 'cpu',
|
||||
color: '#8DC6BC',
|
||||
data: load.map((yValue, index: number) => ({
|
||||
x: index + 1,
|
||||
y: yValue,
|
||||
})),
|
||||
},
|
||||
]
|
||||
const currentLoad =
|
||||
chartData[0].data.length > 0 ? chartData[0].data[chartData[0].data.length - 1].y : 0
|
||||
const chartData: ChartData[] = [
|
||||
{
|
||||
id: 'cpu',
|
||||
color: '#8DC6BC',
|
||||
data: load.map((yValue, index: number) => ({
|
||||
x: index + 1,
|
||||
y: yValue,
|
||||
})),
|
||||
},
|
||||
]
|
||||
const currentLoad =
|
||||
chartData[0].data.length > 0 ? chartData[0].data[chartData[0].data.length - 1].y : 0
|
||||
|
||||
const message = currentLoad < 80 ? 'Good' : 'Poor'
|
||||
const message = currentLoad < 80 ? 'Good' : 'Poor'
|
||||
|
||||
return (
|
||||
<Shadow
|
||||
variant="$2"
|
||||
style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
}}
|
||||
return (
|
||||
<Shadow
|
||||
variant="$2"
|
||||
style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
}}
|
||||
>
|
||||
<YStack>
|
||||
<XStack
|
||||
justifyContent="space-between"
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<YStack>
|
||||
<XStack
|
||||
justifyContent="space-between"
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<div style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}>
|
||||
<StandartLineChart data={chartData} />
|
||||
</div>
|
||||
<YStack space={'$3'}>
|
||||
<Paragraph color={'#09101C'} size={'$6'} fontWeight={'600'}>
|
||||
CPU
|
||||
</Paragraph>
|
||||
<Paragraph color={'#09101C'} size={'$8'} fontWeight={'700'}>
|
||||
{currentLoad} GB
|
||||
</Paragraph>
|
||||
</YStack>
|
||||
</XStack>
|
||||
<Separator borderColor={'#e3e3e3'} />
|
||||
<XStack space={'$4'} style={{ padding: '10px 16px 10px 16px' }}>
|
||||
<IconText
|
||||
icon={message === 'Good' ? <Icon src='icons/active.svg' width={16} /> : <IncorrectIcon size={16} />}
|
||||
weight={'semibold'}
|
||||
>
|
||||
{message}
|
||||
</IconText>
|
||||
{message === 'Poor' && (
|
||||
<Text size={13} color="#E95460">
|
||||
{((currentLoad / 80) * 100).toFixed(0)}% Utilization
|
||||
</Text>
|
||||
)}
|
||||
</XStack>
|
||||
</YStack>
|
||||
</Shadow >
|
||||
)
|
||||
<div style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}>
|
||||
<StandartLineChart data={chartData} />
|
||||
</div>
|
||||
<YStack space={'$3'}>
|
||||
<Paragraph color={'#09101C'} size={'$6'} fontWeight={'600'}>
|
||||
CPU
|
||||
</Paragraph>
|
||||
<Paragraph color={'#09101C'} size={'$8'} fontWeight={'700'}>
|
||||
{currentLoad} GB
|
||||
</Paragraph>
|
||||
</YStack>
|
||||
</XStack>
|
||||
<Separator borderColor={'#e3e3e3'} />
|
||||
<XStack space={'$4'} style={{ padding: '10px 16px 10px 16px' }}>
|
||||
<IconText
|
||||
icon={
|
||||
message === 'Good' ? (
|
||||
<Icon src="icons/active.svg" width={16} />
|
||||
) : (
|
||||
<IncorrectIcon size={16} />
|
||||
)
|
||||
}
|
||||
weight={'semibold'}
|
||||
>
|
||||
{message}
|
||||
</IconText>
|
||||
{message === 'Poor' && (
|
||||
<Text size={13} color="#E95460">
|
||||
{((currentLoad / 80) * 100).toFixed(0)}% Utilization
|
||||
</Text>
|
||||
)}
|
||||
</XStack>
|
||||
</YStack>
|
||||
</Shadow>
|
||||
)
|
||||
}
|
||||
|
||||
export default CPUCard
|
||||
|
|
|
@ -14,6 +14,6 @@ const meta = {
|
|||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Page: Story = {
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
||||
|
|
|
@ -1,75 +1,86 @@
|
|||
import { Shadow, Text } from '@status-im/components';
|
||||
import { Stack, XStack, YStack } from 'tamagui';
|
||||
import UptimeChart from '../UptimeChart/UptimeChart';
|
||||
import Icon from '../../../components/General/Icon';
|
||||
const data: DataItem[] = [
|
||||
{
|
||||
// @NOTE: if you want to add name in the XAxis. You need to set the names here
|
||||
// name: 'Jan',
|
||||
pv: 1,
|
||||
pa: 1,
|
||||
},
|
||||
{
|
||||
// name: 'Feb',
|
||||
pv: 0,
|
||||
pa: 0
|
||||
},
|
||||
{
|
||||
//name: 'Feb',
|
||||
pv: 1,
|
||||
pa: 0
|
||||
},
|
||||
{
|
||||
//name: 'Feb',
|
||||
pv: 0,
|
||||
pa: 0
|
||||
},
|
||||
{
|
||||
//name: 'Feb',
|
||||
pv: 0,
|
||||
pa: 0
|
||||
},
|
||||
{
|
||||
//name: 'Feb',
|
||||
pv: 1,
|
||||
pa: 1
|
||||
},
|
||||
{
|
||||
//name: 'Feb',
|
||||
pv: 1,
|
||||
pa: 1
|
||||
},
|
||||
];
|
||||
interface DataItem {
|
||||
name?: string;
|
||||
pa: number;
|
||||
pv: number;
|
||||
}
|
||||
const ConsensusUptimeCard = () => {
|
||||
return (
|
||||
<Shadow
|
||||
variant="$2"
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
}}
|
||||
>
|
||||
<YStack space={'$3'} width={'260px'} height={'156px'} padding={'$3'}>
|
||||
<YStack>
|
||||
<Text size={15} weight={'semibold'}> Consensus Uptime</Text>
|
||||
<XStack style={{ alignItems: 'end', }} space={'$2'} >
|
||||
<Text size={27} weight={'semibold'}>98%</Text>
|
||||
<Icon src='/icons/positive.svg' width={13}></Icon>
|
||||
<Text size={13} color="#E95460" >1.56%</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
<XStack height={'50%'} justifyContent="center" alignItems="center">
|
||||
<Stack style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', width: '228px', height: '100%' }}>
|
||||
<UptimeChart data={data} />
|
||||
</Stack>
|
||||
</XStack>
|
||||
</YStack>
|
||||
import { Shadow, Text } from '@status-im/components'
|
||||
import { Stack, XStack, YStack } from 'tamagui'
|
||||
|
||||
</Shadow >
|
||||
);
|
||||
import UptimeChart from '../UptimeChart/UptimeChart'
|
||||
import Icon from '../../../components/General/Icon'
|
||||
|
||||
const data: DataItem[] = [
|
||||
{
|
||||
// @NOTE: if you want to add name in the XAxis. You need to set the names here
|
||||
// name: 'Jan',
|
||||
pv: 1,
|
||||
pa: 1,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 1,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 1,
|
||||
pa: 1,
|
||||
},
|
||||
{
|
||||
pv: 1,
|
||||
pa: 1,
|
||||
},
|
||||
]
|
||||
|
||||
type DataItem = {
|
||||
name?: string
|
||||
pa: number
|
||||
pv: number
|
||||
}
|
||||
export default ConsensusUptimeCard;
|
||||
|
||||
const ConsensusUptimeCard = () => {
|
||||
return (
|
||||
<Shadow
|
||||
variant="$2"
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
}}
|
||||
>
|
||||
<YStack space={'$3'} width={'260px'} height={'156px'} padding={'$3'}>
|
||||
<YStack>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
Consensus Uptime
|
||||
</Text>
|
||||
<XStack style={{ alignItems: 'end' }} space={'$2'}>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
98%
|
||||
</Text>
|
||||
<Icon src="/icons/positive.svg" width={13}></Icon>
|
||||
<Text size={13} color="#E95460">
|
||||
1.56%
|
||||
</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
<XStack height={'50%'} justifyContent="center" alignItems="center">
|
||||
<Stack
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
width: '228px',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<UptimeChart data={data} />
|
||||
</Stack>
|
||||
</XStack>
|
||||
</YStack>
|
||||
</Shadow>
|
||||
)
|
||||
}
|
||||
export default ConsensusUptimeCard
|
||||
|
|
|
@ -3,22 +3,24 @@ import { XStack, YStack } from 'tamagui'
|
|||
import BasicInfoCards from './BasicInfoCards/BasicInfoCards'
|
||||
import AddCardsContainer from '../../components/General/AddCards/AddCardsContainer'
|
||||
import SyncStatusCard from './SyncStatusCard/SyncStatusCard'
|
||||
import BalanceChardCard from './BalanceLineChart/BalanceChardCard'
|
||||
import BalanceChartCard from './BalanceChartCard/BalanceChartCard'
|
||||
import CPUCard from './CPULoad/CPUCard'
|
||||
import ConsensusUptimeCard from './ConsensusUptime/ConsensusUptimeCard'
|
||||
import ExecutionUptime from './ExecutionUptime/ExecutionUptime'
|
||||
import DeviceUptime from './DeviceUptime/DeviceUptime'
|
||||
import TitleLogo from './TitleLogo'
|
||||
|
||||
const Dashboard = () => {
|
||||
return (
|
||||
<YStack space={'$4'} alignItems="start">
|
||||
<TitleLogo />
|
||||
<XStack space={'$4'} style={{ width: '100%' }}>
|
||||
<XStack space={'$4'}>
|
||||
<AddCardsContainer />
|
||||
<SyncStatusCard />
|
||||
</XStack>
|
||||
<BalanceChardCard />
|
||||
<CPUCard load={[12, 31, 3, 2, 24,]} />
|
||||
<BalanceChartCard />
|
||||
<CPUCard load={[12, 31, 3, 2, 24]} />
|
||||
</XStack>
|
||||
<BasicInfoCards />
|
||||
<XStack space="$3">
|
||||
|
|
|
@ -14,6 +14,6 @@ const meta = {
|
|||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Page: Story = {
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
||||
|
|
|
@ -1,70 +1,85 @@
|
|||
import { Shadow, Text } from '@status-im/components';
|
||||
import { Stack, XStack, YStack } from 'tamagui';
|
||||
import Icon from '../../../components/General/Icon';
|
||||
import UptimeChart from '../UptimeChart/UptimeChart';
|
||||
import { Shadow, Text } from '@status-im/components'
|
||||
import { Stack, XStack, YStack } from 'tamagui'
|
||||
|
||||
import Icon from '../../../components/General/Icon'
|
||||
import UptimeChart from '../UptimeChart/UptimeChart'
|
||||
|
||||
const data: DataItem[] = [
|
||||
{
|
||||
// @NOTE: if you want to add name in the XAxis. You need to set the names here
|
||||
pv: 1,
|
||||
pa: 1,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 1
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0
|
||||
},
|
||||
{
|
||||
pv: 1,
|
||||
pa: 0
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 1
|
||||
},
|
||||
];
|
||||
{
|
||||
// @NOTE: if you want to add name in the XAxis. You need to set the names here
|
||||
pv: 1,
|
||||
pa: 1,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 1,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 1,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 1,
|
||||
},
|
||||
]
|
||||
|
||||
interface DataItem {
|
||||
name?: string;
|
||||
pa: number;
|
||||
pv: number;
|
||||
type DataItem = {
|
||||
name?: string
|
||||
pa: number
|
||||
pv: number
|
||||
}
|
||||
|
||||
const ExecutionUptime = () => {
|
||||
return (
|
||||
<Shadow
|
||||
variant="$2"
|
||||
return (
|
||||
<Shadow
|
||||
variant="$2"
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
}}
|
||||
>
|
||||
<YStack space={'$3'} width={'260px'} height={'156px'} padding={'$3'}>
|
||||
<YStack>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
Execution Uptime
|
||||
</Text>
|
||||
<XStack style={{ alignItems: 'end' }} space={'$2'}>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
99%
|
||||
</Text>
|
||||
<Icon src="/icons/positive.svg" width={13}></Icon>
|
||||
<Text size={13} color="#E95460">
|
||||
2%
|
||||
</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
<XStack height={'50%'} justifyContent="center" alignItems="center">
|
||||
<Stack
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
width: '228px',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<YStack space={'$3'} width={'260px'} height={'156px'} padding={'$3'}>
|
||||
<YStack>
|
||||
<Text size={15} weight={'semibold'}> Execution Uptime</Text>
|
||||
<XStack style={{ alignItems: 'end', }} space={'$2'} >
|
||||
<Text size={27} weight={'semibold'}>99%</Text>
|
||||
<Icon src='/icons/positive.svg' width={13}></Icon>
|
||||
<Text size={13} color="#E95460" >2%</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
<XStack height={'50%'} justifyContent="center" alignItems="center">
|
||||
<Stack style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', width: '228px', height: '100%' }}>
|
||||
<UptimeChart data={data} />
|
||||
</Stack>
|
||||
</XStack>
|
||||
</YStack>
|
||||
</Shadow >
|
||||
);
|
||||
>
|
||||
<UptimeChart data={data} />
|
||||
</Stack>
|
||||
</XStack>
|
||||
</YStack>
|
||||
</Shadow>
|
||||
)
|
||||
}
|
||||
export default ExecutionUptime;
|
||||
export default ExecutionUptime
|
||||
|
|
|
@ -14,6 +14,38 @@ const meta = {
|
|||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: { title: 'Sync Status', total: 113220, value: 50000 },
|
||||
export const ExecutionClient: Story = {
|
||||
args: { title: 'Execution Client', value: 123.424, total: 170, isTop: true },
|
||||
}
|
||||
|
||||
export const ConsensusClient: Story = {
|
||||
args: { title: 'Consensus Client', value: 123.424, total: 170, isTop: false },
|
||||
}
|
||||
|
||||
export const WithoutTitle: Story = {
|
||||
args: { title: '', value: 123.424, total: 170 },
|
||||
}
|
||||
|
||||
export const WithZeroValue: Story = {
|
||||
args: { title: 'Consensus Client', value: 0, total: 170 },
|
||||
}
|
||||
|
||||
export const WithZeroTotal: Story = {
|
||||
args: { title: 'Consensus Client', value: 123.424, total: 0 },
|
||||
}
|
||||
|
||||
export const WithZeroValueAndTotal: Story = {
|
||||
args: { title: 'Consensus Client', value: 0, total: 0 },
|
||||
}
|
||||
|
||||
export const WithoutValues: Story = {
|
||||
args: { title: '', value: 0, total: 0 },
|
||||
}
|
||||
|
||||
export const WithTopBorders: Story = {
|
||||
args: { title: '', value: 0, total: 0, isTop: true },
|
||||
}
|
||||
|
||||
export const WithBottomBorders: Story = {
|
||||
args: { title: '', value: 0, total: 0, isTop: false },
|
||||
}
|
||||
|
|
|
@ -1,27 +1,46 @@
|
|||
import { Separator, XStack, YStack } from 'tamagui'
|
||||
import { formatNumberForGauge } from '../../../utilities'
|
||||
import { Text } from '@status-im/components'
|
||||
import { Separator, Stack, XStack, YStack } from 'tamagui'
|
||||
import { Shadow, Text } from '@status-im/components'
|
||||
import { SwapIcon } from '@status-im/icons'
|
||||
import { CSSProperties } from 'react'
|
||||
|
||||
import { formatNumberWithComa } from '../../../utilities'
|
||||
import IconText from '../../../components/General/IconText'
|
||||
|
||||
type SyncCardContentProps = {
|
||||
title: string
|
||||
value: number
|
||||
total: number
|
||||
isTop?: boolean
|
||||
}
|
||||
|
||||
const SyncCardContent = ({ title, value, total }: SyncCardContentProps) => {
|
||||
const SyncCardContent = ({ title, value, total, isTop }: SyncCardContentProps) => {
|
||||
const style: CSSProperties = {}
|
||||
|
||||
if (isTop === true) {
|
||||
style.borderTopLeftRadius = '16px'
|
||||
style.borderTopRightRadius = '16px'
|
||||
} else if (isTop === false) {
|
||||
style.borderBottomLeftRadius = '16px'
|
||||
style.borderBottomRightRadius = '16px'
|
||||
}
|
||||
|
||||
return (
|
||||
<YStack>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
{title}
|
||||
</Text>
|
||||
<Separator borderColor={'#e3e3e3'} />
|
||||
<XStack space={'$2'} style={{ padding: '10px 16px 10px 16px' }}>
|
||||
{/* <IconText icon={<TokenIcon size={16} />}>Syncing</IconText> */}
|
||||
<Text size={13}>
|
||||
{formatNumberForGauge(value)} / {formatNumberForGauge(total)}
|
||||
</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
<Shadow variant="$1" style={style}>
|
||||
<YStack>
|
||||
<Stack style={{ width: '260px', height: '84px', paddingTop: '12px', paddingLeft: '16px' }}>
|
||||
<Text size={15} weight={'semibold'} color="#647084">
|
||||
{title}
|
||||
</Text>
|
||||
</Stack>
|
||||
<Separator borderColor={'#e3e3e3'} />
|
||||
<XStack space={'$3'} style={{ padding: '12px 16px' }}>
|
||||
<IconText icon={<SwapIcon size={16} />}>Syncing</IconText>
|
||||
<Text size={13} weight={'semibold'}>
|
||||
{formatNumberWithComa(value)} / {formatNumberWithComa(total)}
|
||||
</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
</Shadow>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
import { Separator, YStack } from 'tamagui'
|
||||
import { Separator, Stack, YStack } from 'tamagui'
|
||||
import { Text } from '@status-im/components'
|
||||
|
||||
import SyncCardContent from './SyncCardContent'
|
||||
import DashboardCardWrapper from '../DashboardCardWrapper'
|
||||
import { Text } from '@status-im/components'
|
||||
|
||||
const SyncStatusCard = () => {
|
||||
return (
|
||||
<DashboardCardWrapper padding="0">
|
||||
<YStack space={'$2'}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
Sync Status
|
||||
</Text>
|
||||
<Stack style={{ paddingTop: '12px', paddingLeft: '16px' }}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
Sync Status
|
||||
</Text>
|
||||
</Stack>
|
||||
<YStack>
|
||||
<SyncCardContent title={'Execution Client'} value={123.424} total={170.0} />
|
||||
<SyncCardContent title={'Execution Client'} value={123.424} total={170} isTop={true} />
|
||||
<Separator borderColor={'#e3e3e3'} />
|
||||
<SyncCardContent title={'Consensus Client'} value={123.424} total={170.0} />
|
||||
<SyncCardContent title={'Consensus Client'} value={123.424} total={170} isTop={false} />
|
||||
</YStack>
|
||||
</YStack>
|
||||
</DashboardCardWrapper>
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import BalanceChardCard from './BalanceChardCard'
|
||||
import TitleLogo from './TitleLogo'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/BalanceChardCard',
|
||||
component: BalanceChardCard,
|
||||
title: 'Dashboard/TitleLogo',
|
||||
component: TitleLogo,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof BalanceChardCard>
|
||||
} satisfies Meta<typeof TitleLogo>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Page: Story = {
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import { Text } from '@status-im/components'
|
||||
import { XStack, YStack } from 'tamagui'
|
||||
|
||||
const TitleLogo = () => {
|
||||
return (
|
||||
<XStack>
|
||||
{/* <Avatar type="icon" size={80} icon={<img src={'/icons/dashboard-logo.png'} />} /> */}
|
||||
<YStack>
|
||||
<Text size={27} color="#09101C" weight={'semibold'}>
|
||||
Nimbus
|
||||
</Text>
|
||||
<Text size={19} color="#647084">
|
||||
Node Management Dashboard
|
||||
</Text>
|
||||
</YStack>
|
||||
</XStack>
|
||||
)
|
||||
}
|
||||
|
||||
export default TitleLogo
|
|
@ -0,0 +1,21 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import UptimeChart from './UptimeChart'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/UptimeChart',
|
||||
component: UptimeChart,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof UptimeChart>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
data: [],
|
||||
},
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
import { BarChart, Bar, ResponsiveContainer, XAxis } from 'recharts';
|
||||
|
||||
interface DataItem {
|
||||
name?: string;
|
||||
pa: number;
|
||||
pv: number;
|
||||
type DataItem = {
|
||||
name?: string
|
||||
pa: number
|
||||
pv: number
|
||||
}
|
||||
|
||||
type UptimeChartProps = {
|
||||
data: DataItem[];
|
||||
data: DataItem[]
|
||||
}
|
||||
|
||||
const UptimeChart = ({ data }: UptimeChartProps) => {
|
||||
|
@ -27,4 +27,5 @@ const UptimeChart = ({ data }: UptimeChartProps) => {
|
|||
</ResponsiveContainer>
|
||||
);
|
||||
}
|
||||
export default UptimeChart;
|
||||
|
||||
export default UptimeChart
|
||||
|
|
|
@ -40,8 +40,8 @@ const DeviceSyncStatus = () => {
|
|||
subtitle="Monitor your Validator Client and Beacon Node syncing progression."
|
||||
/>
|
||||
<YStack style={{ width: '100%' }}>
|
||||
<SyncStatusCardExecution synced={132.432} total={200.0} />
|
||||
<SyncStatusCardConsensus synced={149.5} total={160.0} />
|
||||
<SyncStatusCardExecution synced={132.432} total={200} />
|
||||
<SyncStatusCardConsensus synced={149.5} total={160} />
|
||||
</YStack>
|
||||
<Stack style={{ marginTop: '1rem' }}>
|
||||
<Button>Continue</Button>
|
||||
|
|
|
@ -5,7 +5,7 @@ import Icon from '../../components/General/Icon'
|
|||
import StandardGauge from '../../components/Charts/StandardGauge'
|
||||
import IconText from '../../components/General/IconText'
|
||||
import { TokenIcon } from '@status-im/icons'
|
||||
import { formatNumberForGauge } from '../../utilities'
|
||||
import { formatNumberWithComa } from '../../utilities'
|
||||
|
||||
interface DeviceStorageHealthProps {
|
||||
synced: number
|
||||
|
@ -72,7 +72,7 @@ const SyncStatusCardConsensus: React.FC<DeviceStorageHealthProps> = ({ synced, t
|
|||
<XStack space={'$2'} style={{ padding: '10px 16px 10px 16px' }}>
|
||||
<IconText icon={<TokenIcon size={16} />}>{message}</IconText>
|
||||
<Text size={13}>
|
||||
{formatNumberForGauge(synced)} / {formatNumberForGauge(total)}
|
||||
{formatNumberWithComa(synced)} / {formatNumberWithComa(total)}
|
||||
</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Shadow, Text } from '@status-im/components'
|
|||
import StandardGauge from '../../components/Charts/StandardGauge'
|
||||
import IconText from '../../components/General/IconText'
|
||||
import { TokenIcon } from '@status-im/icons'
|
||||
import { formatNumberForGauge } from '../../utilities'
|
||||
import { formatNumberWithComa } from '../../utilities'
|
||||
|
||||
interface DeviceStorageHealthProps {
|
||||
synced: number
|
||||
|
@ -73,7 +73,7 @@ const SyncStatusCardExecution: React.FC<DeviceStorageHealthProps> = ({ synced, t
|
|||
<XStack space={'$2'} style={{ padding: '10px 16px 10px 16px' }}>
|
||||
<IconText icon={<TokenIcon size={16} />}>{message}</IconText>
|
||||
<Text size={13}>
|
||||
{formatNumberForGauge(synced)} / {formatNumberForGauge(total)}
|
||||
{formatNumberWithComa(synced)} / {formatNumberWithComa(total)}
|
||||
</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Stack, XStack, YStack } from 'tamagui'
|
||||
import StandardGauge from '../../../components/Charts/StandardGauge'
|
||||
import { Text } from '@status-im/components'
|
||||
import { formatNumberForGauge } from '../../../utilities'
|
||||
import { formatNumberWithComa } from '../../../utilities'
|
||||
|
||||
type ActivationSyncCardProps = {
|
||||
gaugeColor: string
|
||||
|
@ -37,7 +37,7 @@ const ActivationSyncCard = ({ gaugeColor, gaugeSynced, gaugeTotal }: ActivationS
|
|||
</Stack>
|
||||
<YStack>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
{formatNumberForGauge(gaugeSynced)} / {formatNumberForGauge(gaugeTotal)}
|
||||
{formatNumberWithComa(gaugeSynced)} / {formatNumberWithComa(gaugeTotal)}
|
||||
</Text>
|
||||
</YStack>
|
||||
</XStack>
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Text } from '@status-im/components'
|
|||
|
||||
import StandardGauge from '../../../../components/Charts/StandardGauge'
|
||||
import BorderBox from '../../../../components/General/BorderBox'
|
||||
import { formatNumberForGauge } from '../../../../utilities'
|
||||
import { formatNumberWithComa } from '../../../../utilities'
|
||||
|
||||
type KeyGenerationSyncCardProps = {
|
||||
synced: number
|
||||
|
@ -45,7 +45,7 @@ const KeyGenerationSyncCard = ({ synced, total, title, color }: KeyGenerationSyn
|
|||
{title}
|
||||
</Text>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
{formatNumberForGauge(synced)} / {formatNumberForGauge(total)}
|
||||
{formatNumberWithComa(synced)} / {formatNumberWithComa(total)}
|
||||
</Text>
|
||||
</YStack>
|
||||
<ClearIcon size={20} color="#A1ABBD" />
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Text } from '@status-im/components'
|
|||
|
||||
import StandardGauge from '../../../../components/Charts/StandardGauge'
|
||||
import BorderBox from '../../../../components/General/BorderBox'
|
||||
import { formatNumberForGauge } from '../../../../utilities'
|
||||
import { formatNumberWithComa } from '../../../../utilities'
|
||||
|
||||
type ConsensusGaugeCardProps = {
|
||||
synced: number
|
||||
|
@ -45,7 +45,7 @@ const ConsensusGaugeCard = ({ synced, total, title, color }: ConsensusGaugeCardP
|
|||
{title}
|
||||
</Text>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
{formatNumberForGauge(synced)} / {formatNumberForGauge(total)}
|
||||
{formatNumberWithComa(synced)} / {formatNumberWithComa(total)}
|
||||
</Text>
|
||||
</YStack>
|
||||
<ClearIcon size={20} color="#A1ABBD" />
|
||||
|
|
|
@ -23,6 +23,6 @@ export const convertSecondsToTimerFormat = (seconds: number) => {
|
|||
return `${String(minutes).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
export const formatNumberForGauge = (n: number): string => {
|
||||
return n.toString().replace(/\./g, ',')
|
||||
export const formatNumberWithComa = (n: number): string => {
|
||||
return n.toFixed(3).replace(/\./g, ',')
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue