diff --git a/CHANGELOG.md b/CHANGELOG.md index 41b4115072..ab36efc106 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ ### Fixes +- Fixed performance issue on stake pool list view ([PR 2924](https://github.com/input-output-hk/daedalus/pull/2924)) - Fixed catalyst fund name ([PR 2946](https://github.com/input-output-hk/daedalus/pull/2946)) - Fixed position of popup on syncing screen ([PR 2921](https://github.com/input-output-hk/daedalus/pull/2921)) - Fixed issue with missing character when copying address from PDF ([PR 2925](https://github.com/input-output-hk/daedalus/pull/2925)) @@ -21,7 +22,6 @@ - Fix warning sign displayed when recommend decimals is zero ([PR 2905](https://github.com/input-output-hk/daedalus/pull/2905)) - Fixed discrete tooltip being clipped by loading overlay when stake pools are adjusted ([PR 2902](https://github.com/input-output-hk/daedalus/pull/2902)) - Sets minimum transaction fee to ada input field when tokens are removed ([PR 2918](https://github.com/input-output-hk/daedalus/pull/2918)) -- Fixed performance issue on stake pool list view ([PR 2924](https://github.com/input-output-hk/daedalus/pull/2924)) ### Chores diff --git a/source/renderer/app/components/staking/stake-pools/StakePoolsTable.tsx b/source/renderer/app/components/staking/stake-pools/StakePoolsTable.tsx index c4de320b7e..c30b475c66 100644 --- a/source/renderer/app/components/staking/stake-pools/StakePoolsTable.tsx +++ b/source/renderer/app/components/staking/stake-pools/StakePoolsTable.tsx @@ -7,28 +7,28 @@ import List from 'react-virtualized/dist/commonjs/List'; import WindowScroller from 'react-virtualized/dist/commonjs/WindowScroller'; import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer'; import { Intl } from '../../../types/i18nTypes'; - import { StakingPageScrollContext } from '../layouts/StakingWithNavigation'; import styles from './StakePoolsTable.scss'; import StakePool from '../../../domains/StakePool'; import LoadingSpinner from '../../widgets/LoadingSpinner'; import BorderedBox from '../../widgets/BorderedBox'; -import { StakePoolsTableHeader } from './StakePoolsTableHeader'; +import { StakePoolsTableHeaderCell } from './StakePoolsTableHeaderCell'; import { useSortedStakePoolList, useCreateColumns, -} from './StakePoolsTable.hooks'; + StakePoolsOrder, +} from './hooks'; export const defaultTableOrdering = { - ranking: 'asc', - ticker: 'asc', - saturation: 'asc', - cost: 'asc', - profitMargin: 'asc', - producedBlocks: 'desc', - nonMyopicMemberRewards: 'desc', - pledge: 'asc', - retiring: 'asc', + ranking: StakePoolsOrder.Asc, + ticker: StakePoolsOrder.Asc, + saturation: StakePoolsOrder.Asc, + cost: StakePoolsOrder.Asc, + profitMargin: StakePoolsOrder.Asc, + producedBlocks: StakePoolsOrder.Desc, + nonMyopicMemberRewards: StakePoolsOrder.Desc, + pledge: StakePoolsOrder.Asc, + retiring: StakePoolsOrder.Asc, }; // Maximum number of stake pools for which we do not need to use the preloading const PRELOADER_THRESHOLD = 100; @@ -51,12 +51,12 @@ type Props = { }; type State = { isPreloading: boolean; - stakePoolsOrder: 'asc' | 'desc'; - stakePoolsSortBy: string; + stakePoolsOrder: StakePoolsOrder; + stakePoolsSortBy: keyof StakePool; }; const initialState: State = { isPreloading: true, - stakePoolsOrder: 'asc', + stakePoolsOrder: StakePoolsOrder.Asc, stakePoolsSortBy: 'ranking', }; @@ -81,12 +81,15 @@ function StakePoolsTableComponent({ }, []); const handleSort = useCallback( - (newSortBy: string) => { + (newSortBy: keyof StakePool) => { const { stakePoolsOrder, stakePoolsSortBy } = state; let newOrder = defaultTableOrdering[newSortBy]; if (newSortBy === stakePoolsSortBy) { - newOrder = stakePoolsOrder === 'asc' ? 'desc' : 'asc'; + newOrder = + stakePoolsOrder === StakePoolsOrder.Asc + ? StakePoolsOrder.Desc + : StakePoolsOrder.Asc; } setState((s) => ({ @@ -197,7 +200,7 @@ function StakePoolsTableComponent({ className={styles.tr} > {headerGroup.headers.map((column) => ( - {column.render('Header')} - + ))} ))} diff --git a/source/renderer/app/components/staking/stake-pools/StakePoolsTableHeader.tsx b/source/renderer/app/components/staking/stake-pools/StakePoolsTableHeaderCell.tsx similarity index 86% rename from source/renderer/app/components/staking/stake-pools/StakePoolsTableHeader.tsx rename to source/renderer/app/components/staking/stake-pools/StakePoolsTableHeaderCell.tsx index af2d503765..931b1826c7 100644 --- a/source/renderer/app/components/staking/stake-pools/StakePoolsTableHeader.tsx +++ b/source/renderer/app/components/staking/stake-pools/StakePoolsTableHeaderCell.tsx @@ -17,7 +17,7 @@ type TableHeaderProps = { }; @observer -class StakePoolsTableHeader extends Component { +class StakePoolsTableHeaderCell extends Component { render() { const { name, @@ -27,9 +27,7 @@ class StakePoolsTableHeader extends Component { children, ...headerProps } = this.props; - const isSorted = - name === stakePoolsSortBy || - (name === 'ticker' && stakePoolsSortBy === 'ticker'); + const isSorted = name === stakePoolsSortBy; const defaultOrdering = defaultTableOrdering[name]; const sortIconClasses = classNames([ styles.sortIcon, @@ -50,4 +48,4 @@ class StakePoolsTableHeader extends Component { } } -export { StakePoolsTableHeader }; +export { StakePoolsTableHeaderCell }; diff --git a/source/renderer/app/components/staking/stake-pools/hooks/index.ts b/source/renderer/app/components/staking/stake-pools/hooks/index.ts new file mode 100644 index 0000000000..7e594bc5ff --- /dev/null +++ b/source/renderer/app/components/staking/stake-pools/hooks/index.ts @@ -0,0 +1,5 @@ +export { useCreateColumns } from './useCreateColumns'; +export { + useSortedStakePoolList, + StakePoolsOrder, +} from './useSortedStakePoolList'; diff --git a/source/renderer/app/components/staking/stake-pools/StakePoolsTable.hooks.tsx b/source/renderer/app/components/staking/stake-pools/hooks/useCreateColumns.tsx similarity index 73% rename from source/renderer/app/components/staking/stake-pools/StakePoolsTable.hooks.tsx rename to source/renderer/app/components/staking/stake-pools/hooks/useCreateColumns.tsx index 1c1a0defcf..7009b01409 100644 --- a/source/renderer/app/components/staking/stake-pools/StakePoolsTable.hooks.tsx +++ b/source/renderer/app/components/staking/stake-pools/hooks/useCreateColumns.tsx @@ -1,94 +1,31 @@ import React, { useMemo } from 'react'; -import { orderBy } from 'lodash'; import classNames from 'classnames'; import BigNumber from 'bignumber.js'; import moment from 'moment'; import { FormattedHTMLMessage } from 'react-intl'; +import { Column } from 'react-table'; import { PopOver } from 'react-polymorph/lib/components/PopOver'; -import { PoolPopOver } from '../widgets/PoolPopOver'; -import { Intl } from '../../../types/i18nTypes'; - -import styles from './StakePoolsTable.scss'; -import StakePool from '../../../domains/StakePool'; -import { getColorFromRange, getSaturationColor } from '../../../utils/colors'; +import { PoolPopOver } from '../../widgets/PoolPopOver'; +import { Intl } from '../../../../types/i18nTypes'; +import styles from '../StakePoolsTable.scss'; +import StakePool from '../../../../domains/StakePool'; +import { + getColorFromRange, + getSaturationColor, +} from '../../../../utils/colors'; import { formattedWalletAmount, toFixedUserFormat, -} from '../../../utils/formatters'; -import { messages } from './StakePoolsTable.messages'; - -const ascOrder = 'asc'; -const descOrder = 'desc'; - -export const defaultTableOrdering = { - ranking: ascOrder, - ticker: ascOrder, - saturation: ascOrder, - cost: ascOrder, - profitMargin: ascOrder, - producedBlocks: descOrder, - nonMyopicMemberRewards: descOrder, - pledge: ascOrder, - retiring: ascOrder, -}; - -interface UseSortedStakePoolListArgs { - stakePoolList: StakePool[]; - sortBy: string; - order: 'asc' | 'desc'; -} - -export const useSortedStakePoolList = ({ - stakePoolList, - sortBy, - order, -}: UseSortedStakePoolListArgs) => - useMemo( - () => - orderBy( - stakePoolList.map((stakePool) => { - let calculatedPledge; - let calculatedCost; - let formattedTicker; - - if (sortBy === 'ticker') { - formattedTicker = stakePool.ticker - .replace(/[^\w\s]/gi, '') - .toLowerCase(); - } - - if (sortBy === 'pledge') { - const formattedPledgeValue = stakePool.pledge.toFixed(2); - calculatedPledge = Number( - parseFloat(formattedPledgeValue).toFixed(2) - ); - } - - if (sortBy === 'cost') { - const formattedCostValue = stakePool.cost.toFixed(2); - calculatedCost = Number(parseFloat(formattedCostValue).toFixed(2)); - } - - return { - ...stakePool, - calculatedPledge, - calculatedCost, - formattedTicker, - }; - }), - ['formattedTicker', 'calculatedPledge', 'calculatedCost', sortBy], - [order, order, order, order] - ), - [stakePoolList, order, sortBy] - ); +} from '../../../../utils/formatters'; +import { messages } from '../StakePoolsTable.messages'; type UseCreateColumnsArgs = { currentTheme: string; showWithSelectButton?: boolean; - onSelect?: (...args: Array) => any; + onSelect?: (poolId: string) => void; containerClassName: string; numberOfRankedStakePools: number; - onOpenExternalLink: (...args: Array) => any; + onOpenExternalLink: (url: string) => void; intl: Intl; }; @@ -101,7 +38,7 @@ export const useCreateColumns = ({ containerClassName, showWithSelectButton, }: UseCreateColumnsArgs) => - useMemo( + useMemo[]>( () => [ { id: 'ranking', @@ -120,7 +57,7 @@ export const useCreateColumns = ({ ), accessor: 'ranking', Cell: ({ row }) => { - const { potentialRewards, ranking }: StakePool = row.original; + const { potentialRewards, ranking } = row.original; const memberRewards = new BigNumber(potentialRewards); return ( @@ -143,7 +80,7 @@ export const useCreateColumns = ({ Header: intl.formatMessage(messages.tableHeaderTicker), accessor: 'ticker', Cell: ({ row }) => { - const stakePool: StakePool = row.original; + const stakePool = row.original; const color = getColorFromRange( stakePool.ranking, numberOfRankedStakePools @@ -180,7 +117,7 @@ export const useCreateColumns = ({ ), accessor: 'saturation', Cell: ({ row }) => { - const { saturation }: StakePool = row.original; + const { saturation } = row.original; const progressBarContentClassnames = classNames([ styles.progressBarContent, styles[getSaturationColor(saturation)], @@ -273,7 +210,7 @@ export const useCreateColumns = ({ ), accessor: 'nonMyopicMemberRewards', Cell: ({ row }) => { - const stakePool: StakePool = row.original; + const stakePool = row.original; const memberRewards = new BigNumber(stakePool.potentialRewards); const potentialRewards = formattedWalletAmount(memberRewards); return potentialRewards; @@ -292,7 +229,7 @@ export const useCreateColumns = ({ ), accessor: 'pledge', Cell: ({ row }) => { - const stakePool: StakePool = row.original; + const stakePool = row.original; const pledge = new BigNumber(stakePool.pledge); const pledgeValue = formattedWalletAmount(pledge, false, false); return pledgeValue; @@ -303,7 +240,7 @@ export const useCreateColumns = ({ Header: intl.formatMessage(messages.tableHeaderRetiring), accessor: 'retiring', Cell: ({ row }) => { - const stakePool: StakePool = row.original; + const stakePool = row.original; const retirement = stakePool.retiring && moment(stakePool.retiring).locale(intl.locale).fromNow(true); diff --git a/source/renderer/app/components/staking/stake-pools/hooks/useSortedStakePoolList.tsx b/source/renderer/app/components/staking/stake-pools/hooks/useSortedStakePoolList.tsx new file mode 100644 index 0000000000..2c1dbfc1e7 --- /dev/null +++ b/source/renderer/app/components/staking/stake-pools/hooks/useSortedStakePoolList.tsx @@ -0,0 +1,54 @@ +import { useMemo } from 'react'; +import { orderBy } from 'lodash'; +import StakePool from '../../../../domains/StakePool'; + +export enum StakePoolsOrder { + Asc = 'asc', + Desc = 'desc', +} + +interface UseSortedStakePoolListArgs { + stakePoolList: StakePool[]; + sortBy: keyof StakePool; + order: StakePoolsOrder; +} + +export const useSortedStakePoolList = ({ + stakePoolList, + sortBy, + order, +}: UseSortedStakePoolListArgs) => + useMemo( + () => + orderBy( + stakePoolList.map((stakePool) => { + let calculatedPledge; + let calculatedCost; + let formattedTicker; + + if (sortBy === 'ticker') { + formattedTicker = stakePool.ticker + .replace(/[^\w\s]/gi, '') + .toLowerCase(); + } + + if (sortBy === 'pledge') { + calculatedPledge = parseFloat(stakePool.pledge.toFixed(2)); + } + + if (sortBy === 'cost') { + calculatedCost = parseFloat(stakePool.cost.toFixed(2)); + } + + return { + ...stakePool, + calculatedPledge, + calculatedCost, + formattedTicker, + }; + }), + ['formattedTicker', 'calculatedPledge', 'calculatedCost', sortBy], + [order, order, order, order] + ), + [stakePoolList, order, sortBy] + ); diff --git a/storybook/webpack.config.js b/storybook/webpack.config.js index 61d5ff7a6c..bda2b67914 100644 --- a/storybook/webpack.config.js +++ b/storybook/webpack.config.js @@ -42,10 +42,10 @@ module.exports = async ({ config }) => { 'moment', 'pbkdf2', 'qrcode.react', - // 'react', + 'react', 'react-copy-to-clipboard', 'react-datetime', - // 'react-dom', + 'react-dom', 'react-router', 'react-svg-inline', 'recharts',