Skip to content

Commit

Permalink
More sale details + region info (#11188)
Browse files Browse the repository at this point in the history
* 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
piggydoughnut authored Jan 20, 2025
1 parent 7ebdd9a commit fd45bb8
Show file tree
Hide file tree
Showing 17 changed files with 729 additions and 320 deletions.
4 changes: 2 additions & 2 deletions packages/page-broker/src/Overview/Summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function Summary ({ coreCount, workloadInfos }: Props): React.ReactElement {
<>
<CardSummary
className='media--1200'
label={t('cycle dates')}
label={t('sale dates')}
>
<div>
<div style={{ fontSize: '14px' }}>{estimateTime(currentRegionStart, status?.lastTimeslice * 80, coretimeConstants?.relay)}</div>
Expand All @@ -118,7 +118,7 @@ function Summary ({ coreCount, workloadInfos }: Props): React.ReactElement {
</CardSummary>
<CardSummary
className='media--1200'
label={t('cycle ts')}
label={t('sale ts')}
>
<div>
<div style={{ fontSize: '14px' }}>{currentRegionStart}</div>
Expand Down
29 changes: 16 additions & 13 deletions packages/page-coretime/src/CoretimePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { ChainName } from './types.js';
import React, { useRef } from 'react';
import { Route, Routes } from 'react-router-dom';

import { Tabs } from '@polkadot/react-components';
import { Spinner, Tabs } from '@polkadot/react-components';
import { useCall } from '@polkadot/react-hooks';

import Overview from './Overview/index.js';
Expand Down Expand Up @@ -47,18 +47,21 @@ function CoretimePage ({ api, basePath, className, isApiReady }: Props): React.R
basePath={basePath}
items={itemsRef.current}
/>
<Routes>
<Route path={basePath}>
<Route
element={<Overview chainName={chainName} />}
index
/>
<Route
element={<Sale chainName={chainName} />}
path='sale'
/>
</Route>
</Routes>
{!chainName
? <div><Spinner /></div>
: <Routes>
<Route path={basePath}>
<Route
element={<Overview chainName={chainName} />}
index
/>
<Route
element={<Sale chainName={chainName} />}
path='sale'
/>
</Route>
</Routes>
}
</main>
);
}
Expand Down
8 changes: 4 additions & 4 deletions packages/page-coretime/src/Overview/Summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function Summary ({ chainName, config, constants, parachainCount, saleInfo, stat
const currentRegionStart = saleInfo.regionEnd - config.regionLength * 2;
const { get } = useCoretimeContext();

const cycleNumber = useMemo(() => {
const saleNumber = useMemo(() => {
if (chainName && currentRegionEnd) {
return Math.floor(
(currentRegionEnd - FirstCycleStart.timeslice.coretime[chainName]) / config.regionLength
Expand All @@ -46,7 +46,7 @@ function Summary ({ chainName, config, constants, parachainCount, saleInfo, stat
{status &&
<CardSummary label={t('sale number')}>
<div>
{cycleNumber}
{saleNumber}
</div>
</CardSummary>
}
Expand All @@ -71,15 +71,15 @@ function Summary ({ chainName, config, constants, parachainCount, saleInfo, stat
</section>
<section className='media--1200'>
{status &&
(<CardSummary label={t('cycle dates')}>
(<CardSummary label={t('sale dates')}>
<div>
<div style={{ fontSize: '14px' }}>{get && estimateTime(currentRegionStart, get.blocks.relay(status?.lastTimeslice), constants.relay)}</div>
<div style={{ fontSize: '14px' }}>{get && estimateTime(currentRegionEnd, get.blocks.relay(status?.lastTimeslice), constants.relay)}</div>
</div>
</CardSummary>)
}
{status &&
<CardSummary label={t('cycle ts')}>
<CardSummary label={t('sale ts')}>
<div>
<div style={{ fontSize: '14px' }}>{currentRegionStart}</div>
<div style={{ fontSize: '14px' }}>{currentRegionEnd}</div>
Expand Down
59 changes: 59 additions & 0 deletions packages/page-coretime/src/Sale/PhaseTable.tsx
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);
158 changes: 158 additions & 0 deletions packages/page-coretime/src/Sale/SaleDetailsView.tsx
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;
51 changes: 0 additions & 51 deletions packages/page-coretime/src/Sale/SaleTable.tsx

This file was deleted.

Loading

0 comments on commit fd45bb8

Please sign in to comment.