Skip to content

Commit

Permalink
feat(ux): Simplify pool list, fetch performance on More (#2070)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ross Bulat committed Apr 9, 2024
1 parent 301ce4d commit fb5008d
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 107 deletions.
9 changes: 5 additions & 4 deletions src/contexts/Pools/PoolPerformance/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ export interface PoolPerformanceContextInterface {
}

// Fetching status for keys.
export type PoolPerformanceTasks = Partial<
Record<PoolRewardPointsKey, PoolPerformanceTaskStatus>
export type PoolPerformanceTasks = Record<
PoolRewardPointsKey,
PoolPerformanceTaskStatus
>;

// Performance fetching status.
Expand All @@ -42,10 +43,10 @@ export interface PoolPerformanceTaskStatus {
*/

// Supported reward points batch keys.
export type PoolRewardPointsKey = 'pool_join' | 'pool_page';
export type PoolRewardPointsKey = string;

// Pool reward batches, keyed by batch key.
export type PoolRewardPointsMap = Partial<Record<string, PoolRewardPoints>>;
export type PoolRewardPointsMap = Record<PoolRewardPointsKey, PoolRewardPoints>;

// Pool reward points are keyed by era, then by pool address.

Expand Down
2 changes: 1 addition & 1 deletion src/library/List/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const defaultContext: ListContextInterface = {
};

// The amount of pools per page.
export const poolsPerPage = 21;
export const poolsPerPage = 30;

// The amount of validators per page.
export const validatorsPerPage = 30;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,39 @@ import { faCaretRight } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useTranslation } from 'react-i18next';
import { useOverlay } from 'kits/Overlay/Provider';
import { usePoolPerformance } from 'contexts/Pools/PoolPerformance';
import type { BondedPool } from 'contexts/Pools/BondedPools/types';

export const JoinPool = ({
id,
export const More = ({
pool,
setActiveTab,
disabled,
}: {
id: number;
pool: BondedPool;
setActiveTab: (t: number) => void;
disabled: boolean;
}) => {
const { t } = useTranslation('tips');
const { openCanvas } = useOverlay().canvas;
const { startPoolRewardPointsFetch } = usePoolPerformance();

const { id, addresses } = pool;

// Define a unique pool performance data key
const performanceKey = `pool_page_standalone_${id}`;

return (
<div className="label button-with-text">
<button
type="button"
onClick={() => {
startPoolRewardPointsFetch(performanceKey, [addresses.stash]);
openCanvas({
key: 'JoinPool',
options: {
providedPool: {
id,
performanceBatchKey: 'pool_page',
performanceBatchKey: performanceKey,
},
onJoinCallback: () => setActiveTab(0),
},
Expand Down
89 changes: 28 additions & 61 deletions src/library/ListItem/Labels/PoolBonded.tsx
Original file line number Diff line number Diff line change
@@ -1,78 +1,45 @@
// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only

import { capitalizeFirstLetter, planckToUnit, rmCommas } from '@w3ux/utils';
import { planckToUnit, rmCommas } from '@w3ux/utils';
import BigNumber from 'bignumber.js';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useBondedPools } from 'contexts/Pools/BondedPools';
import { useStaking } from 'contexts/Staking';
import { ValidatorStatusWrapper } from 'library/ListItem/Wrappers';
import type { Pool } from 'library/Pool/types';
import { useNetwork } from 'contexts/Network';
import type { Pool } from 'library/Pool/types';
import { TooltipTrigger } from '../Wrappers';
import { useTranslation } from 'react-i18next';
import { useTooltip } from 'contexts/Tooltip';

export const PoolBonded = ({ pool }: { pool: Pool }) => {
const { t } = useTranslation('library');
const {
networkData: { units, unit },
networkData: {
units,
brand: { token },
},
} = useNetwork();
const { getPoolNominationStatusCode, poolsNominations } = useBondedPools();
const { eraStakers, getNominationsStatusFromTargets } = useStaking();
const { addresses, points } = pool;

// get pool targets from nominations meta batch
const nominations = poolsNominations[pool.id];
const targets = nominations?.targets || [];
const { setTooltipTextAndOpen } = useTooltip();

// store nomination status in state
const [nominationsStatus, setNominationsStatus] =
useState<Record<string, string>>();
const tooltipText = t('bonded');

// update pool nomination status as nominations metadata becomes available.
// we cannot add effect dependencies here as this needs to trigger
// as soon as the component displays. (upon tab change).
const handleNominationsStatus = () => {
setNominationsStatus(
getNominationsStatusFromTargets(addresses.stash, targets)
);
};
const { points } = pool;
const TokenIcon = token;

// recalculate nominations status as app syncs
useEffect(() => {
if (
targets.length &&
nominationsStatus === null &&
eraStakers.stakers.length
) {
handleNominationsStatus();
}
});

// metadata has changed, which means pool items may have been added.
// recalculate nominations status
useEffect(() => {
handleNominationsStatus();
}, [pool, eraStakers.stakers.length, Object.keys(poolsNominations).length]);

// calculate total bonded pool amount
const poolBonded = planckToUnit(new BigNumber(rmCommas(points)), units);

// determine nominations status and display
const nominationStatus = getPoolNominationStatusCode(
nominationsStatus || null
);
// Format total bonded pool amount.
const bonded = planckToUnit(new BigNumber(rmCommas(points)), units);

return (
<ValidatorStatusWrapper $status={nominationStatus} $noMargin>
<h5>
{nominationStatus === null || !eraStakers.stakers.length
? `${t('syncing')}...`
: targets.length
? capitalizeFirstLetter(t(`${nominationStatus}`) ?? '')
: t('notNominating')}
{' / '}
{t('bonded')}: {poolBonded.decimalPlaces(3).toFormat()} {unit}
</h5>
</ValidatorStatusWrapper>
<div className="label pool">
<TooltipTrigger
className="tooltip-trigger-element"
data-tooltip-text={tooltipText}
onMouseMove={() => setTooltipTextAndOpen(tooltipText)}
/>

<TokenIcon
style={{ maxWidth: '1.25rem', height: '1.25rem' }}
className="token"
/>
{bonded.decimalPlaces(0).toFormat()}
</div>
);
};
70 changes: 70 additions & 0 deletions src/library/ListItem/Labels/PoolNominateStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2024 @paritytech/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only

import { capitalizeFirstLetter } from '@w3ux/utils';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useBondedPools } from 'contexts/Pools/BondedPools';
import { useStaking } from 'contexts/Staking';
import { PoolStatusWrapper } from 'library/ListItem/Wrappers';
import type { Pool } from 'library/Pool/types';

export const PoolNominateStatus = ({ pool }: { pool: Pool }) => {
const { t } = useTranslation('library');
const { getPoolNominationStatusCode, poolsNominations } = useBondedPools();
const { eraStakers, getNominationsStatusFromTargets } = useStaking();
const { addresses } = pool;

// get pool targets from nominations meta batch
const nominations = poolsNominations[pool.id];
const targets = nominations?.targets || [];

// store nomination status in state
const [nominationsStatus, setNominationsStatus] =
useState<Record<string, string>>();

// update pool nomination status as nominations metadata becomes available.
// we cannot add effect dependencies here as this needs to trigger
// as soon as the component displays. (upon tab change).
const handleNominationsStatus = () => {
setNominationsStatus(
getNominationsStatusFromTargets(addresses.stash, targets)
);
};

// recalculate nominations status as app syncs
useEffect(() => {
if (
targets.length &&
nominationsStatus === null &&
eraStakers.stakers.length
) {
handleNominationsStatus();
}
});

// metadata has changed, which means pool items may have been added.
// recalculate nominations status
useEffect(() => {
handleNominationsStatus();
}, [pool, eraStakers.stakers.length, Object.keys(poolsNominations).length]);

// determine nominations status and display
const nominationStatus = getPoolNominationStatusCode(
nominationsStatus || null
);

return (
<PoolStatusWrapper $status={nominationStatus}>
<h4>
<span>
{nominationStatus === null || !eraStakers.stakers.length
? `${t('syncing')}...`
: targets.length
? capitalizeFirstLetter(t(`${nominationStatus}`) ?? '')
: t('notNominating')}
</span>
</h4>
</PoolStatusWrapper>
);
};
59 changes: 51 additions & 8 deletions src/library/ListItem/Wrappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const Wrapper = styled.div`
--height-bottom-row: 2.75rem;
}
&.pool-more {
--height-bottom-row: 7.5rem;
--height-bottom-row: 5.75rem;
}
--height-total: calc(var(--height-top-row) + var(--height-bottom-row));
Expand Down Expand Up @@ -63,9 +63,14 @@ export const Wrapper = styled.div`
&.bottom {
height: var(--height-bottom-row);
&.pools {
align-items: flex-start;
}
&.lg {
display: flex;
align-items: center;
> div {
&:first-child {
flex-grow: 1;
Expand Down Expand Up @@ -94,6 +99,10 @@ export const Labels = styled.div`
padding: 0 0 0 0.25rem;
height: inherit;
&.yMargin {
margin-bottom: 0.9rem;
}
button {
background: var(--shimmer-foreground);
padding: 0 0.1rem;
Expand Down Expand Up @@ -129,16 +138,13 @@ export const Labels = styled.div`
align-items: center;
justify-content: center;
font-size: inherit;
margin: 0 0.4em;
@media (min-width: ${SmallFontSizeMaxWidth}px) {
margin: 0 0.35rem;
&.pool {
margin: 0 0.45rem;
}
> .token {
margin-right: 0.25rem;
}
&.button-with-text {
margin-right: 0;
margin: 0.25rem 0 0 0;
button {
color: var(--accent-color-secondary);
Expand Down Expand Up @@ -253,6 +259,43 @@ export const ValidatorStatusWrapper = styled.div<{
}
`;

export const PoolStatusWrapper = styled.div<{
$status: string;
}>`
h4,
h5 {
display: flex;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
h4 {
color: var(--text-color-tertiary);
font-size: 1rem;
padding-top: ${(props) =>
props.$status === 'active' ? '0.15rem' : '0.25rem'};
> span {
color: ${(props) =>
props.$status === 'active'
? 'var(--status-success-color)'
: 'var(--text-color-tertiary)'};
border: 0.75px solid
${(props) =>
props.$status === 'active'
? 'var(--status-success-color)'
: 'transparent'};
padding: ${(props) => (props.$status === 'active' ? '0 0.5rem' : '0')};
border-radius: 0.3rem;
opacity: ${(props) => (props.$status === 'active' ? 1 : 0.6)};
}
}
`;

export const SelectWrapper = styled.button`
background: var(--background-input);
margin: 0 0.75rem 0 0.25rem;
Expand Down
Loading

0 comments on commit fb5008d

Please sign in to comment.