-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
More sale details + region info (#11188)
* added more details of the sale phases to the sale detail, added current region dates on the sale overview, links to other coretime resellers * refactor, separated components for readability * partial lint * arranged white boxes * added dotlake link, added price graph link, visual improvements * fixed incorrect sale times plus added an exception for the second sale on Kusams * lint and tsc * added ui colour * translation * wording change * typo
- Loading branch information
1 parent
7ebdd9a
commit fd45bb8
Showing
17 changed files
with
729 additions
and
320 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Copyright 2017-2025 @polkadot/app-coretime authors & contributors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
import type { PhaseConfig } from '../types.js'; | ||
|
||
import React, { useRef } from 'react'; | ||
|
||
import { styled, Table } from '@polkadot/react-components'; | ||
import { formatNumber } from '@polkadot/util'; | ||
|
||
import { useTranslation } from '../translate.js'; | ||
|
||
interface Props { | ||
phaseInfo: PhaseConfig['config'][keyof PhaseConfig['config']] | ||
} | ||
|
||
const StyledTable = styled(Table)` | ||
border-collapse: collapse; | ||
tr:last-child { | ||
border-bottom: 1px solid #e6e6e6; | ||
} | ||
`; | ||
|
||
function SaleTable ({ phaseInfo }: Props): React.ReactElement<Props> { | ||
const { t } = useTranslation(); | ||
const headerRef = useRef<([React.ReactNode?, string?, number?] | false)[]>([ | ||
[], | ||
[t('Dates'), 'start media--800'], | ||
[t('Blocks (relay)'), 'start'], | ||
[t('Timeslices'), 'start'] | ||
]); | ||
|
||
return ( | ||
<div style={{ maxWidth: '500px' }}> | ||
<StyledTable | ||
emptySpinner={false} | ||
header={headerRef.current} | ||
isSplit={false} | ||
> | ||
<tr> | ||
<td style={{ width: '100px' }}>Start</td> | ||
<td>{phaseInfo.start.date}</td> | ||
<td>{formatNumber(phaseInfo.start.blocks.relay)}</td> | ||
<td>{formatNumber(phaseInfo.start.ts)}</td> | ||
</tr> | ||
<tr> | ||
<td style={{ width: '100px' }}>End</td> | ||
<td>{phaseInfo.end.date}</td> | ||
<td>{formatNumber(phaseInfo.end.blocks.relay)}</td> | ||
<td>{formatNumber(phaseInfo.end.ts)}</td> | ||
</tr> | ||
|
||
</StyledTable> | ||
</div> | ||
); | ||
} | ||
|
||
export default React.memo(SaleTable); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
// Copyright 2017-2025 @polkadot/app-coretime authors & contributors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
import type { ChainName, SaleParameters } from '../types.js'; | ||
|
||
import React, { useCallback } from 'react'; | ||
|
||
import { Button, styled } from '@polkadot/react-components'; | ||
|
||
import { PhaseName } from '../constants.js'; | ||
import { useTranslation } from '../translate.js'; | ||
import PhaseTable from './PhaseTable.js'; | ||
import { SubScanButton } from './SubScanButton.js'; | ||
|
||
const ResponsiveContainer = styled.div` | ||
display: flex; | ||
flex-direction: row; | ||
justify-content: flex-start; | ||
gap: 10rem; | ||
margin-top: 2rem; | ||
@media (max-width: 1000px) { | ||
flex-direction: column; | ||
} | ||
`; | ||
|
||
const Title = styled.h3` | ||
font-weight: bold; | ||
margin-bottom: 1rem; | ||
`; | ||
|
||
const LinkWithLogo = ({ alt, href, logo }: { href: string, logo: string, alt: string }) => { | ||
return ( | ||
<a | ||
href={href} | ||
rel='noopener noreferrer' | ||
target='_blank' | ||
> | ||
<img | ||
alt={alt} | ||
height={25} | ||
src={logo} | ||
/> | ||
</a> | ||
); | ||
}; | ||
|
||
const providers = { | ||
lastic: { | ||
alt: 'Lastic', | ||
href: (chainName: string) => `https://www.lastic.xyz/${chainName}/bulkcore1`, | ||
logo: 'https://www.lastic.xyz/_next/image?url=%2Fassets%2FImages%2FLogos%2Flastic-logo.png&w=384&q=100' | ||
}, | ||
regionx: { | ||
alt: 'RegionX', | ||
href: (chainName: string) => `https://app.regionx.tech/?network=${chainName}`, | ||
logo: 'https://app.regionx.tech/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flogo.8f0fd171.png&w=3840&q=75' | ||
}, | ||
subscan: { | ||
alt: 'Subscan', | ||
href: (chainName: string) => `https://coretime-${chainName}.subscan.io/coretime_dashboard`, | ||
logo: 'https://www.subscan.io/_next/image?url=%2Fwebsite%2Flogo-light.png&w=256&q=75' | ||
} | ||
}; | ||
|
||
const phases = { | ||
[PhaseName.Renewals]: { | ||
description: 'In this phase, core owners can renew existing cores at a fixed price to ensure continued operation in the next region. No new core purchases are permitted.', | ||
name: 'Interlude/Renewals phase' | ||
}, | ||
[PhaseName.PriceDiscovery]: { | ||
description: 'The period during which cores are available for both purchase and renewal. The price decreases linearly over time.', | ||
name: 'Price Discovery phase' | ||
}, | ||
[PhaseName.FixedPrice]: { | ||
description: 'The period during which cores are available for both purchase and renewal. The price remains fixed towards the end of the sales period.', | ||
name: 'Fixed price phase' | ||
} | ||
}; | ||
|
||
const SaleDetailsView = ({ chainName, chosenSaleNumber, saleParams }: { saleParams: SaleParameters, chosenSaleNumber: number, chainName: ChainName }) => { | ||
const { t } = useTranslation(); | ||
|
||
const openCoretimeDashboard = useCallback(() => { | ||
window.open('https://data.parity.io/coretime'); | ||
}, []); | ||
|
||
const openSubscanSalePriceGraph = useCallback(() => { | ||
window.open(`https://coretime-${chainName}.subscan.io/coretime_dashboard`); | ||
}, [chainName]); | ||
|
||
if (chosenSaleNumber === -1 || !saleParams) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<ResponsiveContainer> | ||
<div> | ||
<Title>Sale phases</Title> | ||
<div style={{ display: 'grid', gap: '1rem', gridTemplateRows: '1fr 1fr 1fr', minWidth: '200px' }}> | ||
{!saleParams?.phaseConfig && | ||
<div> | ||
<p>{t(`This sale is of unsual length of ${saleParams.currentRegion.end.ts - saleParams.currentRegion.start.ts} timeslices, hence the regular phases are not applicable.`)}</p> | ||
<p>{t(`Sale start timeslice: ${saleParams.currentRegion.start.ts}`)}</p> | ||
<p>{t(`Sale end timeslice: ${saleParams.currentRegion.end.ts}`)}</p> | ||
</div> | ||
} | ||
{saleParams?.phaseConfig && Object.entries(phases).map(([phase, { description, name }]) => ( | ||
<div key={phase}> | ||
<h4>{t(name)}</h4> | ||
<p style={{ maxWidth: '600px', opacity: '0.8' }}>{t(description)}</p> | ||
{saleParams?.phaseConfig && | ||
<PhaseTable | ||
phaseInfo={saleParams?.phaseConfig.config[phase as keyof typeof saleParams.phaseConfig.config]} | ||
/>} | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
<div> | ||
<Title>{t('Region for sale ')}</Title> | ||
<p style={{ maxWidth: '600px', opacity: '0.8' }}>{t('Region is an asset of Coretime. It signifies the upcoming sales period within which a core can be secured by purchasing coretime. Acquiring coretime grants access to a core for the duration of that specific region.')}</p> | ||
{saleParams?.regionForSale && <PhaseTable phaseInfo={saleParams?.regionForSale} />} | ||
<Title>Price graph</Title> | ||
<Button | ||
isBasic | ||
label={t('Open Subscan Sale Price graph')} | ||
onClick={openSubscanSalePriceGraph} | ||
/> | ||
<Title>{t('Core Purchase Transactions')}</Title> | ||
<SubScanButton | ||
chainName={chainName} | ||
chosenSaleNumber={chosenSaleNumber} | ||
currentRegion={saleParams.currentRegion} | ||
/> | ||
<Title>{t('DotLake Coretime Dashboard')}</Title> | ||
<Button | ||
isBasic | ||
label={t('DotLake Coretime Dashboard')} | ||
onClick={openCoretimeDashboard} | ||
/> | ||
<Title>{t('Coretime providers')}</Title> | ||
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}> | ||
{Object.entries(providers).map(([provider, { alt, href, logo }]) => ( | ||
<LinkWithLogo | ||
alt={alt} | ||
href={href(chainName)} | ||
key={provider} | ||
logo={logo} | ||
/> | ||
))} | ||
</div> | ||
</div> | ||
</ResponsiveContainer> | ||
); | ||
}; | ||
|
||
export default SaleDetailsView; |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.