@xyo-network/xl1-react-transaction 1.16.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +165 -0
- package/README.md +2234 -0
- package/dist/browser/confirmation/components/TransactionStackProgress.d.ts +10 -0
- package/dist/browser/confirmation/components/TransactionStackProgress.d.ts.map +1 -0
- package/dist/browser/confirmation/components/TransactionStackProgress.stories.d.ts +13 -0
- package/dist/browser/confirmation/components/TransactionStackProgress.stories.d.ts.map +1 -0
- package/dist/browser/confirmation/components/index.d.ts +2 -0
- package/dist/browser/confirmation/components/index.d.ts.map +1 -0
- package/dist/browser/confirmation/components/support/BlockConfirmationStats.d.ts +9 -0
- package/dist/browser/confirmation/components/support/BlockConfirmationStats.d.ts.map +1 -0
- package/dist/browser/confirmation/components/support/BlockRangeEntryStack.d.ts +17 -0
- package/dist/browser/confirmation/components/support/BlockRangeEntryStack.d.ts.map +1 -0
- package/dist/browser/confirmation/components/support/index.d.ts +3 -0
- package/dist/browser/confirmation/components/support/index.d.ts.map +1 -0
- package/dist/browser/confirmation/helpers/BlockFormatters.d.ts +14 -0
- package/dist/browser/confirmation/helpers/BlockFormatters.d.ts.map +1 -0
- package/dist/browser/confirmation/helpers/blockProgressColor.d.ts +3 -0
- package/dist/browser/confirmation/helpers/blockProgressColor.d.ts.map +1 -0
- package/dist/browser/confirmation/helpers/createFilledRange.d.ts +2 -0
- package/dist/browser/confirmation/helpers/createFilledRange.d.ts.map +1 -0
- package/dist/browser/confirmation/helpers/getBlockProgress.d.ts +2 -0
- package/dist/browser/confirmation/helpers/getBlockProgress.d.ts.map +1 -0
- package/dist/browser/confirmation/helpers/index.d.ts +7 -0
- package/dist/browser/confirmation/helpers/index.d.ts.map +1 -0
- package/dist/browser/confirmation/helpers/isCurrentBlockPassedRange.d.ts +3 -0
- package/dist/browser/confirmation/helpers/isCurrentBlockPassedRange.d.ts.map +1 -0
- package/dist/browser/confirmation/helpers/passedBlocksInRange.d.ts +2 -0
- package/dist/browser/confirmation/helpers/passedBlocksInRange.d.ts.map +1 -0
- package/dist/browser/confirmation/hooks/index.d.ts +2 -0
- package/dist/browser/confirmation/hooks/index.d.ts.map +1 -0
- package/dist/browser/confirmation/hooks/useBlockRangeState.d.ts +9 -0
- package/dist/browser/confirmation/hooks/useBlockRangeState.d.ts.map +1 -0
- package/dist/browser/confirmation/index.d.ts +4 -0
- package/dist/browser/confirmation/index.d.ts.map +1 -0
- package/dist/browser/index.d.ts +2 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.mjs +299 -0
- package/dist/browser/index.mjs.map +1 -0
- package/package.json +77 -0
- package/src/confirmation/components/TransactionStackProgress.stories.tsx +56 -0
- package/src/confirmation/components/TransactionStackProgress.tsx +83 -0
- package/src/confirmation/components/index.ts +1 -0
- package/src/confirmation/components/support/BlockConfirmationStats.tsx +43 -0
- package/src/confirmation/components/support/BlockRangeEntryStack.tsx +64 -0
- package/src/confirmation/components/support/index.ts +2 -0
- package/src/confirmation/helpers/BlockFormatters.ts +52 -0
- package/src/confirmation/helpers/blockProgressColor.ts +15 -0
- package/src/confirmation/helpers/createFilledRange.ts +20 -0
- package/src/confirmation/helpers/getBlockProgress.ts +22 -0
- package/src/confirmation/helpers/index.ts +6 -0
- package/src/confirmation/helpers/isCurrentBlockPassedRange.ts +13 -0
- package/src/confirmation/helpers/passedBlocksInRange.ts +12 -0
- package/src/confirmation/hooks/index.ts +1 -0
- package/src/confirmation/hooks/useBlockRangeState.ts +27 -0
- package/src/confirmation/index.ts +3 -0
- package/src/index.ts +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json.schemastore.org/package.json",
|
|
3
|
+
"name": "@xyo-network/xl1-react-transaction",
|
|
4
|
+
"version": "1.16.23",
|
|
5
|
+
"description": "XYO Layer One API",
|
|
6
|
+
"homepage": "https://xylabs.com",
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "git+https://github.com/xylabs/xyo-chain/issues",
|
|
9
|
+
"email": "support@xylabs.com"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/xylabs/xyo-chain.git"
|
|
14
|
+
},
|
|
15
|
+
"license": "LGPL-3.0-only",
|
|
16
|
+
"author": {
|
|
17
|
+
"name": "XY Labs Development Team",
|
|
18
|
+
"email": "support@xylabs.com",
|
|
19
|
+
"url": "https://xylabs.com"
|
|
20
|
+
},
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"type": "module",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"browser": {
|
|
26
|
+
"types": "./dist/browser/index.d.ts",
|
|
27
|
+
"source": "./src/index.ts",
|
|
28
|
+
"default": "./dist/browser/index.mjs"
|
|
29
|
+
},
|
|
30
|
+
"types": "./dist/browser/index.d.ts",
|
|
31
|
+
"source": "./src/index.ts",
|
|
32
|
+
"default": "./dist/browser/index.mjs"
|
|
33
|
+
},
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
36
|
+
"module": "./dist/browser/index.mjs",
|
|
37
|
+
"source": "./src/index.ts",
|
|
38
|
+
"types": "./dist/browser/index.d.ts",
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"src",
|
|
42
|
+
"!**/*.bench.*",
|
|
43
|
+
"!**/*.spec.*",
|
|
44
|
+
"!**/*.test.*"
|
|
45
|
+
],
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@mui/icons-material": "~7.3.5",
|
|
48
|
+
"@mui/material": "~7.3.5",
|
|
49
|
+
"@xylabs/sdk-js": "~5.0.39",
|
|
50
|
+
"@xyo-network/xl1-protocol": "~1.13.13"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@emotion/react": "~11.14.0",
|
|
54
|
+
"@emotion/styled": "~11.14.1",
|
|
55
|
+
"@storybook/react-vite": "~10.0.8",
|
|
56
|
+
"@types/react": "~19.2.6",
|
|
57
|
+
"@xylabs/ts-scripts-yarn3": "~7.2.8",
|
|
58
|
+
"@xylabs/tsconfig": "~7.2.8",
|
|
59
|
+
"@xylabs/tsconfig-dom": "~7.2.8",
|
|
60
|
+
"@xylabs/tsconfig-react": "~7.2.8",
|
|
61
|
+
"typescript": "~5.9.3"
|
|
62
|
+
},
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"react": "~19.1.1"
|
|
65
|
+
},
|
|
66
|
+
"packageManager": "yarn@4.6.0",
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": ">=22"
|
|
69
|
+
},
|
|
70
|
+
"volta": {
|
|
71
|
+
"node": "22.5.1",
|
|
72
|
+
"yarn": "4.6.0"
|
|
73
|
+
},
|
|
74
|
+
"publishConfig": {
|
|
75
|
+
"access": "public"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { StoryFn } from '@storybook/react-vite'
|
|
2
|
+
import { isUndefined } from '@xylabs/sdk-js'
|
|
3
|
+
import { asBlockRange } from '@xyo-network/xl1-protocol'
|
|
4
|
+
import React, { useEffect, useState } from 'react'
|
|
5
|
+
|
|
6
|
+
import { TransactionStackProgress } from './TransactionStackProgress.tsx'
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
title: 'transaction/stack/progress',
|
|
10
|
+
component: TransactionStackProgress,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const START_BLOCK = 100_001
|
|
14
|
+
const END_BLOCK = 100_010
|
|
15
|
+
|
|
16
|
+
const Template: StoryFn<typeof TransactionStackProgress> = args => <TransactionStackProgress {...args} />
|
|
17
|
+
const TemplateWithChangingValues: StoryFn<typeof TransactionStackProgress> = (args) => {
|
|
18
|
+
const [currentBlockNumber, setCurrentBlockNumber] = useState<number>()
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const interval = setInterval(() => {
|
|
21
|
+
setCurrentBlockNumber((prev) => {
|
|
22
|
+
if (isUndefined(prev)) {
|
|
23
|
+
return START_BLOCK
|
|
24
|
+
}
|
|
25
|
+
if (prev >= END_BLOCK + 2) {
|
|
26
|
+
return START_BLOCK
|
|
27
|
+
}
|
|
28
|
+
return prev + 1
|
|
29
|
+
})
|
|
30
|
+
}, 1000)
|
|
31
|
+
return () => clearInterval(interval)
|
|
32
|
+
}, [])
|
|
33
|
+
return <TransactionStackProgress currentBlockNumber={currentBlockNumber} {...args} />
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const Default = Template.bind({})
|
|
37
|
+
Default.args = {}
|
|
38
|
+
|
|
39
|
+
const WithValues = Template.bind({})
|
|
40
|
+
WithValues.args = { currentBlockNumber: 100_003, blockRange: asBlockRange([START_BLOCK, END_BLOCK]) }
|
|
41
|
+
|
|
42
|
+
const WithConfirmed = Template.bind({})
|
|
43
|
+
WithConfirmed.args = {
|
|
44
|
+
currentBlockNumber: 100_004, blockRange: asBlockRange([START_BLOCK, END_BLOCK]), confirmedInBlock: 100_004,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const WithExpired = Template.bind({})
|
|
48
|
+
WithExpired.args = { currentBlockNumber: END_BLOCK + 2, blockRange: asBlockRange([START_BLOCK, END_BLOCK]) }
|
|
49
|
+
|
|
50
|
+
const WithChangingValues = TemplateWithChangingValues.bind({})
|
|
51
|
+
WithChangingValues.args = { blockRange: asBlockRange([START_BLOCK, END_BLOCK]) }
|
|
52
|
+
|
|
53
|
+
export {
|
|
54
|
+
Default, WithChangingValues, WithConfirmed, WithExpired,
|
|
55
|
+
WithValues,
|
|
56
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { StackProps } from '@mui/material'
|
|
2
|
+
import { LinearProgress, Stack } from '@mui/material'
|
|
3
|
+
import { isDefined } from '@xylabs/sdk-js'
|
|
4
|
+
import { type BlockRange } from '@xyo-network/xl1-protocol'
|
|
5
|
+
import React, {
|
|
6
|
+
useLayoutEffect,
|
|
7
|
+
useMemo,
|
|
8
|
+
useRef, useState,
|
|
9
|
+
} from 'react'
|
|
10
|
+
|
|
11
|
+
import { BlockFormatters, getBlockProgress } from '../helpers/index.ts'
|
|
12
|
+
import { useBlockRangeState } from '../hooks/index.ts'
|
|
13
|
+
import { BlockConfirmationStats, BlockRangeEntryStack } from './support/index.ts'
|
|
14
|
+
|
|
15
|
+
export interface TransactionStackProgressProps extends StackProps {
|
|
16
|
+
blockRange?: BlockRange
|
|
17
|
+
confirmedInBlock?: number
|
|
18
|
+
currentBlockNumber?: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const TransactionStackProgress: React.FC<TransactionStackProgressProps> = ({
|
|
22
|
+
blockRange, confirmedInBlock, currentBlockNumber, ...props
|
|
23
|
+
}) => {
|
|
24
|
+
const blockPositionRefs = useRef<{ [blockNumber: number]: HTMLSpanElement | null }>({})
|
|
25
|
+
const progressElementRef = useRef<HTMLDivElement | null>(null)
|
|
26
|
+
|
|
27
|
+
const {
|
|
28
|
+
passedBlocks, progressColor, range, isConfirmed, isExpired,
|
|
29
|
+
} = useBlockRangeState(blockRange, confirmedInBlock, currentBlockNumber)
|
|
30
|
+
|
|
31
|
+
const blockFormatters = useMemo(() => new BlockFormatters({ confirmedInBlock, currentBlockNumber }), [confirmedInBlock, currentBlockNumber])
|
|
32
|
+
|
|
33
|
+
const [progressValue, setProgressValue] = useState(0)
|
|
34
|
+
|
|
35
|
+
useLayoutEffect(() => {
|
|
36
|
+
// prevent updates if the current block is past the confirmed block
|
|
37
|
+
if (isDefined(currentBlockNumber) && isDefined(confirmedInBlock) && currentBlockNumber > confirmedInBlock) {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
const currentBlockNumberElement = isDefined(currentBlockNumber) ? blockPositionRefs.current[currentBlockNumber] : null
|
|
41
|
+
const progressElement = progressElementRef.current
|
|
42
|
+
// since we are relying on htmlElements, we have to use layout effect
|
|
43
|
+
// eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect
|
|
44
|
+
setProgressValue(getBlockProgress(
|
|
45
|
+
currentBlockNumber,
|
|
46
|
+
currentBlockNumberElement,
|
|
47
|
+
progressElement,
|
|
48
|
+
))
|
|
49
|
+
}, [currentBlockNumber])
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<Stack direction="row" {...props}>
|
|
53
|
+
<Stack width="100%" gap={1}>
|
|
54
|
+
<Stack>
|
|
55
|
+
<LinearProgress ref={progressElementRef} variant="determinate" value={isExpired ? 100 : progressValue} color={progressColor} />
|
|
56
|
+
<Stack direction="row" justifyContent="space-between">
|
|
57
|
+
{range.map((block) => {
|
|
58
|
+
const blockColor = blockFormatters.color(block)
|
|
59
|
+
const blockStatus = blockFormatters.confirmationStatus(block)
|
|
60
|
+
const formattedBlockNumber = blockFormatters.formatNumber(block)
|
|
61
|
+
return (
|
|
62
|
+
<BlockRangeEntryStack
|
|
63
|
+
key={block}
|
|
64
|
+
blockPositionRefs={blockPositionRefs}
|
|
65
|
+
block={block}
|
|
66
|
+
blockColor={blockColor}
|
|
67
|
+
blockStatus={blockStatus}
|
|
68
|
+
formattedBlockNumber={formattedBlockNumber}
|
|
69
|
+
/>
|
|
70
|
+
)
|
|
71
|
+
})}
|
|
72
|
+
</Stack>
|
|
73
|
+
</Stack>
|
|
74
|
+
<BlockConfirmationStats
|
|
75
|
+
confirmed={isConfirmed}
|
|
76
|
+
currentBlockColor={isDefined(currentBlockNumber) ? blockFormatters.color(currentBlockNumber) : 'text.secondary'}
|
|
77
|
+
currentBlockNumberValue={isDefined(currentBlockNumber) ? new Intl.NumberFormat().format(currentBlockNumber) : 'N/A'}
|
|
78
|
+
passedBlocks={passedBlocks}
|
|
79
|
+
/>
|
|
80
|
+
</Stack>
|
|
81
|
+
</Stack>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TransactionStackProgress.tsx'
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CheckCircleOutline } from '@mui/icons-material'
|
|
2
|
+
import {
|
|
3
|
+
Grow, Stack, Typography,
|
|
4
|
+
} from '@mui/material'
|
|
5
|
+
import { isDefined } from '@xylabs/sdk-js'
|
|
6
|
+
import React from 'react'
|
|
7
|
+
|
|
8
|
+
export interface BlockConfirmationStatsProps {
|
|
9
|
+
confirmed?: boolean
|
|
10
|
+
currentBlockColor?: string
|
|
11
|
+
currentBlockNumberValue?: string
|
|
12
|
+
passedBlocks?: number[]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const BlockConfirmationStats: React.FC<BlockConfirmationStatsProps> = ({
|
|
16
|
+
confirmed, currentBlockColor, currentBlockNumberValue, passedBlocks,
|
|
17
|
+
}) => {
|
|
18
|
+
return (
|
|
19
|
+
<Stack>
|
|
20
|
+
<Typography
|
|
21
|
+
variant="caption"
|
|
22
|
+
color={currentBlockColor}
|
|
23
|
+
sx={{
|
|
24
|
+
display: 'inline-flex', alignItems: 'center', gap: 0.5,
|
|
25
|
+
}}
|
|
26
|
+
>
|
|
27
|
+
Current Block:
|
|
28
|
+
{' '}
|
|
29
|
+
{currentBlockNumberValue}
|
|
30
|
+
{' '}
|
|
31
|
+
<Grow in={confirmed}>
|
|
32
|
+
<CheckCircleOutline sx={{ width: '0.8em', height: '0.8em' }} color="success" />
|
|
33
|
+
</Grow>
|
|
34
|
+
</Typography>
|
|
35
|
+
<Typography variant="caption" color="warning.light" sx={{ opacity: 0.75 }}>
|
|
36
|
+
Passed Blocks:
|
|
37
|
+
{' '}
|
|
38
|
+
{isDefined(passedBlocks) && passedBlocks.length > 0 ? passedBlocks.map(block => new Intl.NumberFormat().format(block)).join(', ') : 'N/A'}
|
|
39
|
+
</Typography>
|
|
40
|
+
|
|
41
|
+
</Stack>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { BoxProps, StackProps } from '@mui/material'
|
|
2
|
+
import {
|
|
3
|
+
Box, Stack, styled, Tooltip, Typography,
|
|
4
|
+
} from '@mui/material'
|
|
5
|
+
import React from 'react'
|
|
6
|
+
|
|
7
|
+
import type { BlockConfirmationStatus } from '../../helpers/index.ts'
|
|
8
|
+
|
|
9
|
+
export interface BlockRangeEntryStackProps extends StackProps {
|
|
10
|
+
block: number
|
|
11
|
+
blockColor: string
|
|
12
|
+
blockPositionRefs: React.RefObject<{ [blockNumber: number]: HTMLSpanElement | null }>
|
|
13
|
+
blockStatus: BlockConfirmationStatus | undefined
|
|
14
|
+
formattedBlockNumber: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const BlockRangeEntryStack: React.FC<BlockRangeEntryStackProps> = ({
|
|
18
|
+
blockPositionRefs, block, blockColor, blockStatus, formattedBlockNumber, sx, ...props
|
|
19
|
+
}) => {
|
|
20
|
+
return (
|
|
21
|
+
<Stack
|
|
22
|
+
ref={(ref) => { blockPositionRefs.current[block] = ref }}
|
|
23
|
+
key={block}
|
|
24
|
+
sx={{ position: 'relative', ...sx }}
|
|
25
|
+
{...props}
|
|
26
|
+
>
|
|
27
|
+
<Box
|
|
28
|
+
component="span"
|
|
29
|
+
sx={{
|
|
30
|
+
display: 'flex', position: 'relative', width: '100%', height: 5,
|
|
31
|
+
}}
|
|
32
|
+
>
|
|
33
|
+
<StyledBlockNumberIndicator component="span" sx={{ backgroundColor: blockColor }} />
|
|
34
|
+
</Box>
|
|
35
|
+
<Tooltip
|
|
36
|
+
title={`Block: ${new Intl.NumberFormat().format(block)} (${blockStatus})`}
|
|
37
|
+
placement="top"
|
|
38
|
+
arrow
|
|
39
|
+
>
|
|
40
|
+
<Typography
|
|
41
|
+
variant="caption"
|
|
42
|
+
sx={{
|
|
43
|
+
color: blockColor,
|
|
44
|
+
cursor: 'pointer',
|
|
45
|
+
opacity: blockStatus === 'missed' ? 0.75 : 1,
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
{formattedBlockNumber}
|
|
49
|
+
</Typography>
|
|
50
|
+
</Tooltip>
|
|
51
|
+
</Stack>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const StyledBlockNumberIndicator = styled(Box, { name: 'StyledBlockNumberIndicator' })<BoxProps>(({ theme }) => {
|
|
56
|
+
return theme.unstable_sx({
|
|
57
|
+
position: 'absolute',
|
|
58
|
+
left: 'calc(50% - 1px)',
|
|
59
|
+
transform: 'calc(translateX(-50%) - 1px)',
|
|
60
|
+
height: 3,
|
|
61
|
+
width: '1px',
|
|
62
|
+
backgroundColor: 'primary.main',
|
|
63
|
+
})
|
|
64
|
+
})
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { isDefined } from '@xylabs/sdk-js'
|
|
2
|
+
|
|
3
|
+
export type BlockConfirmationStatus = 'confirmed' | 'missed' | 'pending'
|
|
4
|
+
|
|
5
|
+
type BlockFormattersParams = {
|
|
6
|
+
confirmedInBlock: number | undefined
|
|
7
|
+
currentBlockNumber: number | undefined
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class BlockFormatters {
|
|
11
|
+
private readonly params: BlockFormattersParams
|
|
12
|
+
|
|
13
|
+
constructor(params: BlockFormattersParams) {
|
|
14
|
+
this.params = params
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
color(blockNumber: number): string {
|
|
18
|
+
const { currentBlockNumber, confirmedInBlock } = this.params
|
|
19
|
+
if (blockNumber === currentBlockNumber) {
|
|
20
|
+
return isDefined(confirmedInBlock) && confirmedInBlock === blockNumber ? 'success.dark' : 'text'
|
|
21
|
+
}
|
|
22
|
+
const status = this.confirmationStatus(blockNumber)
|
|
23
|
+
switch (status) {
|
|
24
|
+
case 'confirmed': {
|
|
25
|
+
return 'success.dark'
|
|
26
|
+
}
|
|
27
|
+
case 'missed': {
|
|
28
|
+
return 'warning.light'
|
|
29
|
+
}
|
|
30
|
+
case 'pending': {
|
|
31
|
+
return 'text.secondary'
|
|
32
|
+
}
|
|
33
|
+
default: {
|
|
34
|
+
return 'text.secondary'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
confirmationStatus(blockNumber: number): BlockConfirmationStatus | undefined {
|
|
40
|
+
const { currentBlockNumber, confirmedInBlock } = this.params
|
|
41
|
+
if (isDefined(currentBlockNumber)) {
|
|
42
|
+
if (isDefined(confirmedInBlock) && blockNumber === confirmedInBlock) {
|
|
43
|
+
return 'confirmed'
|
|
44
|
+
}
|
|
45
|
+
return currentBlockNumber > blockNumber ? 'missed' : 'pending'
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
formatNumber(blockNumber: number) {
|
|
50
|
+
return blockNumber.toString().length <= 5 ? new Intl.NumberFormat().format(blockNumber) : `${blockNumber.toString().slice(-2)}`
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { LinearProgressProps } from '@mui/material'
|
|
2
|
+
import { isDefined } from '@xylabs/sdk-js'
|
|
3
|
+
|
|
4
|
+
export const blockProgressColor = (
|
|
5
|
+
confirmedInBlock: number | undefined,
|
|
6
|
+
isExpired: boolean | undefined,
|
|
7
|
+
): LinearProgressProps['color'] => {
|
|
8
|
+
if (isDefined(confirmedInBlock)) {
|
|
9
|
+
return 'success'
|
|
10
|
+
}
|
|
11
|
+
if (isExpired) {
|
|
12
|
+
return 'error'
|
|
13
|
+
}
|
|
14
|
+
return 'primary'
|
|
15
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { isUndefined } from '@xylabs/sdk-js'
|
|
2
|
+
|
|
3
|
+
export const createFilledRange = (range?: [number, number]): number[] => {
|
|
4
|
+
if (isUndefined(range)) {
|
|
5
|
+
return []
|
|
6
|
+
}
|
|
7
|
+
const [start, end] = range
|
|
8
|
+
if (end < start) {
|
|
9
|
+
console.warn('Invalid range: end is less than start')
|
|
10
|
+
return []
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const result: number[] = []
|
|
14
|
+
|
|
15
|
+
for (let i = start; i <= end; i++) {
|
|
16
|
+
result.push(i)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return result
|
|
20
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { isUndefined, isUndefinedOrNull } from '@xylabs/sdk-js'
|
|
2
|
+
|
|
3
|
+
export const getBlockProgress = (
|
|
4
|
+
currentBlockNumber: number | undefined,
|
|
5
|
+
currentBlockRef: HTMLSpanElement | null,
|
|
6
|
+
progressElementRef: HTMLDivElement | null,
|
|
7
|
+
) => {
|
|
8
|
+
if (isUndefined(currentBlockNumber) || isUndefinedOrNull(currentBlockRef) || isUndefinedOrNull(progressElementRef)) {
|
|
9
|
+
return 0
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const currentBlockOffsetLeft = currentBlockRef.offsetLeft
|
|
13
|
+
const currentBlockOffsetWidth = currentBlockRef.clientWidth / 2
|
|
14
|
+
const currentBlockCenterOffsetLeft = currentBlockOffsetLeft + currentBlockOffsetWidth
|
|
15
|
+
const parentOffsetLeft = progressElementRef.offsetLeft
|
|
16
|
+
const parentWidth = progressElementRef.clientWidth
|
|
17
|
+
|
|
18
|
+
const relativePosition = currentBlockCenterOffsetLeft - parentOffsetLeft
|
|
19
|
+
const progress = (relativePosition / parentWidth) * 100
|
|
20
|
+
|
|
21
|
+
return Math.min(Math.max(progress, 0), 100)
|
|
22
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { isDefined } from '@xylabs/sdk-js'
|
|
2
|
+
import type { BlockRange } from '@xyo-network/xl1-protocol'
|
|
3
|
+
|
|
4
|
+
export const isCurrentBlockPassedRange = (
|
|
5
|
+
blockRange: BlockRange | undefined,
|
|
6
|
+
currentBlockNumber: number | undefined,
|
|
7
|
+
) => {
|
|
8
|
+
if (!isDefined(blockRange) || !isDefined(currentBlockNumber)) {
|
|
9
|
+
return false
|
|
10
|
+
}
|
|
11
|
+
const [, end] = blockRange
|
|
12
|
+
return currentBlockNumber > end
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { isDefined } from '@xylabs/sdk-js'
|
|
2
|
+
|
|
3
|
+
export const passedBlocksInRange = (
|
|
4
|
+
range: number[] | undefined,
|
|
5
|
+
currentBlockNumber: number | undefined,
|
|
6
|
+
) => {
|
|
7
|
+
if (!isDefined(currentBlockNumber) || !isDefined(range)) {
|
|
8
|
+
return []
|
|
9
|
+
}
|
|
10
|
+
const [start] = range
|
|
11
|
+
return range.filter(block => block < currentBlockNumber && block >= start)
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useBlockRangeState.ts'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { isDefined } from '@xylabs/sdk-js'
|
|
2
|
+
import type { BlockRange } from '@xyo-network/xl1-protocol'
|
|
3
|
+
import { useMemo } from 'react'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
blockProgressColor, createFilledRange, isCurrentBlockPassedRange, passedBlocksInRange,
|
|
7
|
+
} from '../helpers/index.ts'
|
|
8
|
+
|
|
9
|
+
export const useBlockRangeState = (
|
|
10
|
+
blockRange: BlockRange | undefined,
|
|
11
|
+
confirmedInBlock: number | undefined,
|
|
12
|
+
currentBlockNumber?: number | undefined,
|
|
13
|
+
) => {
|
|
14
|
+
const range = useMemo(() => createFilledRange((blockRange)), [blockRange])
|
|
15
|
+
|
|
16
|
+
const isExpired = useMemo(() => isCurrentBlockPassedRange(blockRange, currentBlockNumber), [blockRange, currentBlockNumber])
|
|
17
|
+
|
|
18
|
+
const passedBlocks = useMemo(() => passedBlocksInRange(range, currentBlockNumber), [currentBlockNumber, range])
|
|
19
|
+
|
|
20
|
+
const progressColor = useMemo(() => blockProgressColor(confirmedInBlock, isExpired), [confirmedInBlock, isExpired])
|
|
21
|
+
|
|
22
|
+
const isConfirmed = isDefined(confirmedInBlock)
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
isConfirmed, isExpired, passedBlocks, progressColor, range,
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './confirmation/index.ts'
|