feat: update postage stamp creation screen (#641)
* style: UI changes for postage stamp * feat: New postage stamp standard page --------- Co-authored-by: Seres Roland <seresroland@Seres-MBP.home>
This commit is contained in:
Generated
+23
-23
@@ -9,7 +9,7 @@
|
|||||||
"version": "0.24.1",
|
"version": "0.24.1",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ethersphere/bee-js": "^6.2.0",
|
"@ethersphere/bee-js": "^6.6.0",
|
||||||
"@ethersphere/swarm-cid": "^0.1.0",
|
"@ethersphere/swarm-cid": "^0.1.0",
|
||||||
"@material-ui/core": "4.12.3",
|
"@material-ui/core": "4.12.3",
|
||||||
"@material-ui/icons": "4.11.2",
|
"@material-ui/icons": "4.11.2",
|
||||||
@@ -2440,13 +2440,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ethersphere/bee-js": {
|
"node_modules/@ethersphere/bee-js": {
|
||||||
"version": "6.2.0",
|
"version": "6.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ethersphere/bee-js/-/bee-js-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ethersphere/bee-js/-/bee-js-6.6.0.tgz",
|
||||||
"integrity": "sha512-QWuVvW+c9z+AFWuRL+YBZECDyV3G5qeD9L0J7Tx7HYMugoDjMAjeRyNHjkf0a5np57q3i9MAE2P678rjSJ1Yaw==",
|
"integrity": "sha512-f39yEbkCX7mnKSn0x9cV2TAlnMiemiJCiTVLhS6+g7nMbud1r269gzEHopElDaP5VJIsJy1uwD0VN4+HxIp3bg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ethersphere/swarm-cid": "^0.1.0",
|
"@ethersphere/swarm-cid": "^0.1.0",
|
||||||
"@types/readable-stream": "^2.3.13",
|
"@types/readable-stream": "^2.3.13",
|
||||||
"axios": "^1.3.4",
|
"axios": "^0.27.2",
|
||||||
"cafe-utility": "^10.8.1",
|
"cafe-utility": "^10.8.1",
|
||||||
"elliptic": "^6.5.4",
|
"elliptic": "^6.5.4",
|
||||||
"fetch-blob": "2.1.2",
|
"fetch-blob": "2.1.2",
|
||||||
@@ -2466,13 +2466,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ethersphere/bee-js/node_modules/axios": {
|
"node_modules/@ethersphere/bee-js/node_modules/axios": {
|
||||||
"version": "1.3.4",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||||
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
|
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.0",
|
"follow-redirects": "^1.14.9",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0"
|
||||||
"proxy-from-env": "^1.1.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ethersphere/bee-js/node_modules/form-data": {
|
"node_modules/@ethersphere/bee-js/node_modules/form-data": {
|
||||||
@@ -16491,7 +16490,8 @@
|
|||||||
"node_modules/proxy-from-env": {
|
"node_modules/proxy-from-env": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/psl": {
|
"node_modules/psl": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
@@ -22305,13 +22305,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@ethersphere/bee-js": {
|
"@ethersphere/bee-js": {
|
||||||
"version": "6.2.0",
|
"version": "6.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ethersphere/bee-js/-/bee-js-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ethersphere/bee-js/-/bee-js-6.6.0.tgz",
|
||||||
"integrity": "sha512-QWuVvW+c9z+AFWuRL+YBZECDyV3G5qeD9L0J7Tx7HYMugoDjMAjeRyNHjkf0a5np57q3i9MAE2P678rjSJ1Yaw==",
|
"integrity": "sha512-f39yEbkCX7mnKSn0x9cV2TAlnMiemiJCiTVLhS6+g7nMbud1r269gzEHopElDaP5VJIsJy1uwD0VN4+HxIp3bg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ethersphere/swarm-cid": "^0.1.0",
|
"@ethersphere/swarm-cid": "^0.1.0",
|
||||||
"@types/readable-stream": "^2.3.13",
|
"@types/readable-stream": "^2.3.13",
|
||||||
"axios": "^1.3.4",
|
"axios": "^0.27.2",
|
||||||
"cafe-utility": "^10.8.1",
|
"cafe-utility": "^10.8.1",
|
||||||
"elliptic": "^6.5.4",
|
"elliptic": "^6.5.4",
|
||||||
"fetch-blob": "2.1.2",
|
"fetch-blob": "2.1.2",
|
||||||
@@ -22324,13 +22324,12 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "1.3.4",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||||
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
|
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"follow-redirects": "^1.15.0",
|
"follow-redirects": "^1.14.9",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0"
|
||||||
"proxy-from-env": "^1.1.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"form-data": {
|
"form-data": {
|
||||||
@@ -32620,7 +32619,8 @@
|
|||||||
"proxy-from-env": {
|
"proxy-from-env": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"psl": {
|
"psl": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@
|
|||||||
"url": "https://github.com/ethersphere/bee-dashboard.git"
|
"url": "https://github.com/ethersphere/bee-dashboard.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ethersphere/bee-js": "^6.2.0",
|
"@ethersphere/bee-js": "^6.6.0",
|
||||||
"@ethersphere/swarm-cid": "^0.1.0",
|
"@ethersphere/swarm-cid": "^0.1.0",
|
||||||
"@material-ui/core": "4.12.3",
|
"@material-ui/core": "4.12.3",
|
||||||
"@material-ui/icons": "4.11.2",
|
"@material-ui/icons": "4.11.2",
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export function AccountStamps(): ReactElement {
|
|||||||
if (status.all === CheckState.ERROR) return <TroubleshootConnectionCard />
|
if (status.all === CheckState.ERROR) return <TroubleshootConnectionCard />
|
||||||
|
|
||||||
function navigateToNewStamp() {
|
function navigateToNewStamp() {
|
||||||
navigate(ROUTES.ACCOUNT_STAMPS_NEW)
|
navigate(ROUTES.ACCOUNT_STAMPS_NEW_STANDARD)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { detectIndexHtml, getAssetNameFromFiles, packageFile } from '../../utils
|
|||||||
import { persistIdentity, updateFeed } from '../../utils/identity'
|
import { persistIdentity, updateFeed } from '../../utils/identity'
|
||||||
import { HISTORY_KEYS, putHistory } from '../../utils/local-storage'
|
import { HISTORY_KEYS, putHistory } from '../../utils/local-storage'
|
||||||
import { FeedPasswordDialog } from '../feeds/FeedPasswordDialog'
|
import { FeedPasswordDialog } from '../feeds/FeedPasswordDialog'
|
||||||
import { PostageStampCreation } from '../stamps/PostageStampCreation'
|
import { PostageStampAdvancedCreation } from '../stamps/PostageStampAdvancedCreation'
|
||||||
import { PostageStampSelector } from '../stamps/PostageStampSelector'
|
import { PostageStampSelector } from '../stamps/PostageStampSelector'
|
||||||
import { AssetPreview } from './AssetPreview'
|
import { AssetPreview } from './AssetPreview'
|
||||||
import { StampPreview } from './StampPreview'
|
import { StampPreview } from './StampPreview'
|
||||||
@@ -186,7 +186,7 @@ export function Upload(): ReactElement {
|
|||||||
{hasAnyStamps && stampMode === 'SELECT' ? (
|
{hasAnyStamps && stampMode === 'SELECT' ? (
|
||||||
<PostageStampSelector onSelect={stamp => setStamp(stamp)} defaultValue={stamp?.batchID} />
|
<PostageStampSelector onSelect={stamp => setStamp(stamp)} defaultValue={stamp?.batchID} />
|
||||||
) : (
|
) : (
|
||||||
<PostageStampCreation onFinished={() => setStampMode('SELECT')} />
|
<PostageStampAdvancedCreation onFinished={() => setStampMode('SELECT')} />
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Box mb={4}>
|
<Box mb={4}>
|
||||||
|
|||||||
+3
-3
@@ -2,7 +2,7 @@ import { ReactElement } from 'react'
|
|||||||
import { useNavigate } from 'react-router'
|
import { useNavigate } from 'react-router'
|
||||||
import { HistoryHeader } from '../../components/HistoryHeader'
|
import { HistoryHeader } from '../../components/HistoryHeader'
|
||||||
import { ROUTES } from '../../routes'
|
import { ROUTES } from '../../routes'
|
||||||
import { PostageStampCreation } from './PostageStampCreation'
|
import { PostageStampAdvancedCreation } from './PostageStampAdvancedCreation'
|
||||||
|
|
||||||
export function CreatePostageStampPage(): ReactElement {
|
export function CreatePostageStampPage(): ReactElement {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
@@ -13,8 +13,8 @@ export function CreatePostageStampPage(): ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<HistoryHeader>Buy new postage stamp</HistoryHeader>
|
<HistoryHeader>Buy new postage stamp batch</HistoryHeader>
|
||||||
<PostageStampCreation onFinished={onFinished} />
|
<PostageStampAdvancedCreation onFinished={onFinished} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { ReactElement } from 'react'
|
||||||
|
import { useNavigate } from 'react-router'
|
||||||
|
import { HistoryHeader } from '../../components/HistoryHeader'
|
||||||
|
import { ROUTES } from '../../routes'
|
||||||
|
import { PostageStampStandardCreation } from './PostageStampStandardCreation'
|
||||||
|
|
||||||
|
export function CreatePostageStampBasicPage(): ReactElement {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
function onFinished() {
|
||||||
|
navigate(ROUTES.ACCOUNT_STAMPS)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<HistoryHeader>Buy new postage stamp batch</HistoryHeader>
|
||||||
|
<PostageStampStandardCreation onFinished={onFinished} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
+63
-53
@@ -1,5 +1,6 @@
|
|||||||
import { PostageBatchOptions } from '@ethersphere/bee-js'
|
import { PostageBatchOptions } from '@ethersphere/bee-js'
|
||||||
import { Box, Grid, Typography } from '@material-ui/core'
|
import { Box, Grid, Typography } from '@material-ui/core'
|
||||||
|
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
|
||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import { useSnackbar } from 'notistack'
|
import { useSnackbar } from 'notistack'
|
||||||
import { ReactElement, useContext, useState } from 'react'
|
import { ReactElement, useContext, useState } from 'react'
|
||||||
@@ -18,12 +19,32 @@ import {
|
|||||||
waitUntilStampExists,
|
waitUntilStampExists,
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
import { getHumanReadableFileSize } from '../../utils/file'
|
import { getHumanReadableFileSize } from '../../utils/file'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { ROUTES } from '../../routes'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onFinished: () => void
|
onFinished: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PostageStampCreation({ onFinished }: Props): ReactElement {
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
|
createStyles({
|
||||||
|
link: {
|
||||||
|
color: '#dd7700',
|
||||||
|
textDecoration: 'underline',
|
||||||
|
'&:hover': {
|
||||||
|
textDecoration: 'none',
|
||||||
|
|
||||||
|
// https://github.com/mui-org/material-ui/issues/22543
|
||||||
|
'@media (hover: none)': {
|
||||||
|
textDecoration: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
export function PostageStampAdvancedCreation({ onFinished }: Props): ReactElement {
|
||||||
|
const classes = useStyles()
|
||||||
const { chainState } = useContext(BeeContext)
|
const { chainState } = useContext(BeeContext)
|
||||||
const { refresh } = useContext(StampsContext)
|
const { refresh } = useContext(StampsContext)
|
||||||
const { beeDebugApi } = useContext(SettingsContext)
|
const { beeDebugApi } = useContext(SettingsContext)
|
||||||
@@ -153,22 +174,25 @@ export function PostageStampCreation({ onFinished }: Props): ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box mb={4}>
|
<Box mb={1}>
|
||||||
<Typography>
|
<Typography variant="h2">Batch name</Typography>
|
||||||
To upload data to Swarm network, you will need to purchase a postage stamp. If you're not familiar with
|
|
||||||
this, please read{' '}
|
|
||||||
<a
|
|
||||||
href="https://medium.com/ethereum-swarm/how-to-upload-data-to-the-swarm-network-c0766c3ae381"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
this guide
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
</Box>
|
||||||
<Box mb={2}>
|
<Box mb={2}>
|
||||||
<SwarmTextInput name="depth" label="Depth" onChange={event => validateDepthInput(event.target.value)} />
|
<SwarmTextInput name="label" label="Label" optional onChange={event => setLabelInput(event.target.value)} />
|
||||||
|
</Box>
|
||||||
|
<Box mb={2}>
|
||||||
|
<SwarmSelect
|
||||||
|
label="Immutable"
|
||||||
|
defaultValue="No"
|
||||||
|
onChange={event => setImmutable(event.target.value === 'Yes')}
|
||||||
|
options={[
|
||||||
|
{ value: 'Yes', label: 'Yes' },
|
||||||
|
{ value: 'No', label: 'No' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box mb={2}>
|
||||||
|
<SwarmTextInput name="depth" label="Batch depth" onChange={event => validateDepthInput(event.target.value)} />
|
||||||
<Box mt={0.25} sx={{ bgcolor: '#f6f6f6' }} p={2}>
|
<Box mt={0.25} sx={{ bgcolor: '#f6f6f6' }} p={2}>
|
||||||
<Grid container justifyContent="space-between">
|
<Grid container justifyContent="space-between">
|
||||||
<Typography>Corresponding file size</Typography>
|
<Typography>Corresponding file size</Typography>
|
||||||
@@ -185,38 +209,14 @@ export function PostageStampCreation({ onFinished }: Props): ReactElement {
|
|||||||
<Typography>{!amountError && amountInput ? getTtl(Number.parseInt(amountInput, 10)) : '-'}</Typography>
|
<Typography>{!amountError && amountInput ? getTtl(Number.parseInt(amountInput, 10)) : '-'}</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box display="flex" justifyContent={'right'} mt={0.5}>
|
||||||
|
<Typography style={{ fontSize: '10px', color: 'rgba(0, 0, 0, 0.26)' }}>
|
||||||
|
Current price of 24000 per block
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
{amountError && <Typography>{amountError}</Typography>}
|
{amountError && <Typography>{amountError}</Typography>}
|
||||||
</Box>
|
</Box>
|
||||||
<Box mb={2}>
|
|
||||||
<SwarmTextInput name="label" label="Label" optional onChange={event => setLabelInput(event.target.value)} />
|
|
||||||
</Box>
|
|
||||||
<Box mb={2}>
|
|
||||||
<SwarmSelect
|
|
||||||
label="Immutable"
|
|
||||||
defaultValue="No"
|
|
||||||
onChange={event => setImmutable(event.target.value === 'Yes')}
|
|
||||||
options={[
|
|
||||||
{ value: 'Yes', label: 'Yes' },
|
|
||||||
{ value: 'No', label: 'No' },
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<Box mt={0.25} sx={{ bgcolor: '#f6f6f6' }} p={2}>
|
|
||||||
<Grid container justifyContent="space-between">
|
|
||||||
{immutable && (
|
|
||||||
<Typography>
|
|
||||||
Once an immutable stamp is maxed out, it disallows further content uploads, thereby safeguarding your
|
|
||||||
previously uploaded content from unintentional overwriting.
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
{!immutable && (
|
|
||||||
<Typography>
|
|
||||||
When a mutable stamp reaches full capacity, it still permits new content uploads. However, this comes
|
|
||||||
with the caveat of overwriting previously uploaded content associated with the same stamp.
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</Grid>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<Box mb={4} sx={{ bgcolor: '#fcf2e8' }} p={2}>
|
<Box mb={4} sx={{ bgcolor: '#fcf2e8' }} p={2}>
|
||||||
<Grid container justifyContent="space-between">
|
<Grid container justifyContent="space-between">
|
||||||
<Typography>Indicative Price</Typography>
|
<Typography>Indicative Price</Typography>
|
||||||
@@ -227,14 +227,24 @@ export function PostageStampCreation({ onFinished }: Props): ReactElement {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
<SwarmButton
|
|
||||||
disabled={submitting || Boolean(depthError) || Boolean(amountError) || !depthInput || !amountInput}
|
<Grid container justifyContent="space-between" alignItems="center">
|
||||||
onClick={submit}
|
<Grid item>
|
||||||
iconType={Check}
|
<SwarmButton
|
||||||
loading={submitting}
|
disabled={submitting || Boolean(depthError) || Boolean(amountError) || !depthInput || !amountInput}
|
||||||
>
|
onClick={submit}
|
||||||
Buy New Stamp
|
iconType={Check}
|
||||||
</SwarmButton>
|
loading={submitting}
|
||||||
|
>
|
||||||
|
Buy New Stamp
|
||||||
|
</SwarmButton>
|
||||||
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
<Link to={ROUTES.ACCOUNT_STAMPS_NEW_STANDARD} className={classes.link}>
|
||||||
|
Standard mode
|
||||||
|
</Link>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,230 @@
|
|||||||
|
import { PostageBatchOptions } from '@ethersphere/bee-js'
|
||||||
|
import { Utils } from '@ethersphere/bee-js'
|
||||||
|
import { Box, Button, Grid, Slider, Typography } from '@material-ui/core'
|
||||||
|
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
|
||||||
|
import { useSnackbar } from 'notistack'
|
||||||
|
import { ReactElement, useContext, useState } from 'react'
|
||||||
|
import Check from 'remixicon-react/CheckLineIcon'
|
||||||
|
import { SwarmButton } from '../../components/SwarmButton'
|
||||||
|
import { SwarmTextInput } from '../../components/SwarmTextInput'
|
||||||
|
import { Context as SettingsContext } from '../../providers/Settings'
|
||||||
|
import { Context as StampsContext } from '../../providers/Stamps'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { ROUTES } from '../../routes'
|
||||||
|
import { calculateStampPrice, convertAmountToSeconds, secondsToTimeString, waitUntilStampExists } from '../../utils'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onFinished: () => void
|
||||||
|
}
|
||||||
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
|
createStyles({
|
||||||
|
link: {
|
||||||
|
color: '#dd7700',
|
||||||
|
textDecoration: 'underline',
|
||||||
|
'&:hover': {
|
||||||
|
textDecoration: 'none',
|
||||||
|
|
||||||
|
// https://github.com/mui-org/material-ui/issues/22543
|
||||||
|
'@media (hover: none)': {
|
||||||
|
textDecoration: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
buttonSelected: {
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
const marks = [
|
||||||
|
{ value: 1, label: '1 day' },
|
||||||
|
{ value: 365, label: '365 days' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export function PostageStampStandardCreation({ onFinished }: Props): ReactElement {
|
||||||
|
const getDepthForCapacity = Utils.getDepthForCapacity
|
||||||
|
const getAmountForTtl = Utils.getAmountForTtl
|
||||||
|
const classes = useStyles()
|
||||||
|
const { refresh } = useContext(StampsContext)
|
||||||
|
const { beeDebugApi } = useContext(SettingsContext)
|
||||||
|
|
||||||
|
const [depthInput, setDepthInput] = useState<number>(getDepthForCapacity(4))
|
||||||
|
const [amountInput, setAmountInput] = useState<number>(Number.parseInt(getAmountForTtl(30)))
|
||||||
|
const [labelInput, setLabelInput] = useState('')
|
||||||
|
const [submitting, setSubmitting] = useState(false)
|
||||||
|
const [buttonValue, setButtonValue] = useState(4)
|
||||||
|
|
||||||
|
function sliderValueChange(event: any, newValue: any) {
|
||||||
|
const amountValue = Number.parseInt(getAmountForTtl(newValue))
|
||||||
|
setAmountInput(amountValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { enqueueSnackbar } = useSnackbar()
|
||||||
|
|
||||||
|
function getTtl(amount: number): string {
|
||||||
|
const pricePerBlock = 24000
|
||||||
|
|
||||||
|
return `${secondsToTimeString(
|
||||||
|
convertAmountToSeconds(amount, pricePerBlock),
|
||||||
|
)} (with price of ${pricePerBlock.toFixed(0)} per block)`
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPrice(depth: number, amount: bigint): string {
|
||||||
|
const price = calculateStampPrice(depth, amount)
|
||||||
|
|
||||||
|
return `${price.toSignificantDigits()} xBZZ`
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submit() {
|
||||||
|
try {
|
||||||
|
// This is really just a typeguard, the validation pretty much guarantees these will have the right values
|
||||||
|
if (!depthInput || !amountInput) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!beeDebugApi) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setSubmitting(true)
|
||||||
|
const amount = BigInt(amountInput)
|
||||||
|
const depth = depthInput
|
||||||
|
const options: PostageBatchOptions = {
|
||||||
|
waitForUsable: false,
|
||||||
|
label: labelInput || undefined,
|
||||||
|
immutableFlag: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const batchId = await beeDebugApi.createPostageBatch(amount.toString(), depth, options)
|
||||||
|
await waitUntilStampExists(batchId, beeDebugApi)
|
||||||
|
await refresh()
|
||||||
|
onFinished()
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e) // eslint-disable-line
|
||||||
|
enqueueSnackbar(`Error: ${(e as Error).message}`, { variant: 'error' })
|
||||||
|
}
|
||||||
|
setSubmitting(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBatchSize(event: any) {
|
||||||
|
let value = event.target.innerText
|
||||||
|
value = Number(value.substring(0, value.length - 3))
|
||||||
|
setButtonValue(value)
|
||||||
|
const capacity = getDepthForCapacity(value)
|
||||||
|
setDepthInput(capacity)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box mb={4}>
|
||||||
|
<Typography>
|
||||||
|
A postage stamp batch containes postage stamps that will give you the right to upload data to the Swarm
|
||||||
|
network. If you're not familiar with this, please read
|
||||||
|
<a
|
||||||
|
href="https://medium.com/ethereum-swarm/how-to-upload-data-to-the-swarm-network-c0766c3ae381"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
this guide
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box mb={1}>
|
||||||
|
<Typography variant="h2">Batch name</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box mb={2}>
|
||||||
|
<SwarmTextInput name="depth" label="Label" onChange={e => setLabelInput(e.target.value)} />
|
||||||
|
</Box>
|
||||||
|
<Box mb={1}>
|
||||||
|
<Typography variant="h2">Batch size</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box mb={2}>
|
||||||
|
<Grid container justifyContent="space-between" spacing={2}>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
fullWidth
|
||||||
|
onClick={handleBatchSize}
|
||||||
|
className={buttonValue === 4 ? classes.buttonSelected : ''}
|
||||||
|
>
|
||||||
|
4 GB
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
fullWidth
|
||||||
|
onClick={handleBatchSize}
|
||||||
|
className={buttonValue === 32 ? classes.buttonSelected : ''}
|
||||||
|
>
|
||||||
|
32 GB
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
fullWidth
|
||||||
|
onClick={handleBatchSize}
|
||||||
|
className={buttonValue === 256 ? classes.buttonSelected : ''}
|
||||||
|
>
|
||||||
|
256 GB
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
<Box mb={1}>
|
||||||
|
<Typography variant="h2">Data persistence</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box mb={2}>
|
||||||
|
<Slider
|
||||||
|
aria-label="Volume"
|
||||||
|
min={1}
|
||||||
|
max={365}
|
||||||
|
step={1}
|
||||||
|
marks={marks}
|
||||||
|
valueLabelDisplay="auto"
|
||||||
|
defaultValue={30}
|
||||||
|
onChange={sliderValueChange}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box mb={2}>
|
||||||
|
<Box mt={0.25} sx={{ bgcolor: '#f6f6f6' }} p={2}>
|
||||||
|
<Grid container justifyContent="space-between">
|
||||||
|
<Typography>Corresponding TTL (Time to live)</Typography>
|
||||||
|
<Typography>{amountInput ? getTtl(amountInput) : '-'}</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
<Box display="flex" justifyContent={'right'} mt={0.5}>
|
||||||
|
<Typography style={{ fontSize: '10px', color: 'rgba(0, 0, 0, 0.26)' }}>
|
||||||
|
Current price of 24000 per block
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box mb={4} sx={{ bgcolor: '#fcf2e8' }} p={2}>
|
||||||
|
<Grid container justifyContent="space-between">
|
||||||
|
<Typography>Indicative Price</Typography>
|
||||||
|
<Typography>{getPrice(depthInput, BigInt(amountInput))}</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
<Grid container justifyContent="space-between" alignItems="center">
|
||||||
|
<Grid item>
|
||||||
|
<SwarmButton
|
||||||
|
disabled={submitting || !depthInput || !amountInput}
|
||||||
|
onClick={submit}
|
||||||
|
iconType={Check}
|
||||||
|
loading={submitting}
|
||||||
|
>
|
||||||
|
Buy New Stamp
|
||||||
|
</SwarmButton>
|
||||||
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
<Link to={ROUTES.ACCOUNT_STAMPS_NEW_ADVANCED} className={classes.link}>
|
||||||
|
Advanced mode
|
||||||
|
</Link>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -44,7 +44,7 @@ export default function Stamp(): ReactElement {
|
|||||||
if (status.all === CheckState.ERROR) return <TroubleshootConnectionCard />
|
if (status.all === CheckState.ERROR) return <TroubleshootConnectionCard />
|
||||||
|
|
||||||
function navigateToNewStamp() {
|
function navigateToNewStamp() {
|
||||||
navigate(ROUTES.ACCOUNT_STAMPS_NEW)
|
navigate(ROUTES.ACCOUNT_STAMPS_NEW_STANDARD)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
+6
-3
@@ -16,7 +16,7 @@ import GiftCards from './pages/gift-code'
|
|||||||
import Info from './pages/info'
|
import Info from './pages/info'
|
||||||
import LightModeRestart from './pages/restart/LightModeRestart'
|
import LightModeRestart from './pages/restart/LightModeRestart'
|
||||||
import Settings from './pages/settings'
|
import Settings from './pages/settings'
|
||||||
import { CreatePostageStampPage } from './pages/stamps/CreatePostageStampPage'
|
import { CreatePostageStampPage } from './pages/stamps/CreatePostageStampAdvancedPage'
|
||||||
import Status from './pages/status'
|
import Status from './pages/status'
|
||||||
import TopUp from './pages/top-up'
|
import TopUp from './pages/top-up'
|
||||||
import { BankCardTopUpIndex } from './pages/top-up/BankCardTopUpIndex'
|
import { BankCardTopUpIndex } from './pages/top-up/BankCardTopUpIndex'
|
||||||
@@ -25,6 +25,7 @@ import { GiftCardFund } from './pages/top-up/GiftCardFund'
|
|||||||
import { GiftCardTopUpIndex } from './pages/top-up/GiftCardTopUpIndex'
|
import { GiftCardTopUpIndex } from './pages/top-up/GiftCardTopUpIndex'
|
||||||
import { Swap } from './pages/top-up/Swap'
|
import { Swap } from './pages/top-up/Swap'
|
||||||
import { Context as SettingsContext } from './providers/Settings'
|
import { Context as SettingsContext } from './providers/Settings'
|
||||||
|
import { CreatePostageStampBasicPage } from './pages/stamps/CreatePostageStampStandardPage'
|
||||||
|
|
||||||
export enum ROUTES {
|
export enum ROUTES {
|
||||||
INFO = '/',
|
INFO = '/',
|
||||||
@@ -46,7 +47,8 @@ export enum ROUTES {
|
|||||||
ACCOUNT_WALLET = '/account/wallet',
|
ACCOUNT_WALLET = '/account/wallet',
|
||||||
ACCOUNT_CHEQUEBOOK = '/account/chequebook',
|
ACCOUNT_CHEQUEBOOK = '/account/chequebook',
|
||||||
ACCOUNT_STAMPS = '/account/stamps',
|
ACCOUNT_STAMPS = '/account/stamps',
|
||||||
ACCOUNT_STAMPS_NEW = '/account/stamps/new',
|
ACCOUNT_STAMPS_NEW_STANDARD = '/account/stamps/new',
|
||||||
|
ACCOUNT_STAMPS_NEW_ADVANCED = '/account/stamps/new/advanced',
|
||||||
ACCOUNT_FEEDS = '/account/feeds',
|
ACCOUNT_FEEDS = '/account/feeds',
|
||||||
ACCOUNT_FEEDS_NEW = '/account/feeds/new',
|
ACCOUNT_FEEDS_NEW = '/account/feeds/new',
|
||||||
ACCOUNT_FEEDS_UPDATE = '/account/feeds/update/:hash',
|
ACCOUNT_FEEDS_UPDATE = '/account/feeds/update/:hash',
|
||||||
@@ -86,7 +88,8 @@ const BaseRouter = (): ReactElement => {
|
|||||||
<Route path={ROUTES.ACCOUNT_WALLET} element={<AccountWallet />} />
|
<Route path={ROUTES.ACCOUNT_WALLET} element={<AccountWallet />} />
|
||||||
<Route path={ROUTES.ACCOUNT_CHEQUEBOOK} element={<AccountChequebook />} />
|
<Route path={ROUTES.ACCOUNT_CHEQUEBOOK} element={<AccountChequebook />} />
|
||||||
<Route path={ROUTES.ACCOUNT_STAMPS} element={<AccountStamps />} />
|
<Route path={ROUTES.ACCOUNT_STAMPS} element={<AccountStamps />} />
|
||||||
<Route path={ROUTES.ACCOUNT_STAMPS_NEW} element={<CreatePostageStampPage />} />
|
<Route path={ROUTES.ACCOUNT_STAMPS_NEW_STANDARD} element={<CreatePostageStampBasicPage />} />
|
||||||
|
<Route path={ROUTES.ACCOUNT_STAMPS_NEW_ADVANCED} element={<CreatePostageStampPage />} />
|
||||||
<Route path={ROUTES.ACCOUNT_FEEDS} element={<AccountFeeds />} />
|
<Route path={ROUTES.ACCOUNT_FEEDS} element={<AccountFeeds />} />
|
||||||
<Route path={ROUTES.ACCOUNT_FEEDS_NEW} element={<CreateNewFeed />} />
|
<Route path={ROUTES.ACCOUNT_FEEDS_NEW} element={<CreateNewFeed />} />
|
||||||
<Route path={ROUTES.ACCOUNT_FEEDS_UPDATE} element={<UpdateFeed />} />
|
<Route path={ROUTES.ACCOUNT_FEEDS_UPDATE} element={<UpdateFeed />} />
|
||||||
|
|||||||
@@ -159,6 +159,23 @@ const componentsOverrides = (theme: Theme) => ({
|
|||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
MuiSlider: {
|
||||||
|
root: {
|
||||||
|
'& .MuiSlider-valueLabel': {
|
||||||
|
top: '-27px',
|
||||||
|
'& span': {
|
||||||
|
height: '20px',
|
||||||
|
borderRadius: '0px',
|
||||||
|
transform: 'none',
|
||||||
|
'& span': {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
transform: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const propsOverrides = {
|
const propsOverrides = {
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
export function getStampUsage(utilization: number, depth: number, bucketDepth: number): number {
|
||||||
|
return utilization / Math.pow(2, depth - bucketDepth)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStampMaximumCapacityBytes(depth: number): number {
|
||||||
|
return 2 ** depth * 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStampCostInPlur(depth: number, amount: number): number {
|
||||||
|
return 2 ** depth * amount
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStampCostInBzz(depth: number, amount: number): number {
|
||||||
|
const BZZ_UNIT = 10 ** 16
|
||||||
|
|
||||||
|
return getStampCostInPlur(depth, amount) / BZZ_UNIT
|
||||||
|
}
|
||||||
|
|
||||||
|
// export function getStampTtlSeconds(amount: number, pricePerBlock = 24_000, blockTime = 5): number {
|
||||||
|
// return (amount * blockTime) / pricePerBlock
|
||||||
|
// }
|
||||||
|
|
||||||
|
export function getStampTtlSeconds(amount: number, pricePerBlock = 24_000, blockTime = 5): number {
|
||||||
|
return (amount * blockTime) / pricePerBlock
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user