From 1147e6ee288a4df05479c468bea3692e53cb10fa Mon Sep 17 00:00:00 2001 From: WhiteMind Date: Tue, 7 Nov 2023 10:21:21 +0800 Subject: [PATCH 1/3] Refactor: Organize the code in the service to the appropriate location (#134) * refactor: move the global state in the Sheet component to a more appropriate location * refactor: code related to app settings * refactor: implement cacheService to replace cache utils * refactor: remove useInitApp * feat: remove an unnecessary chain alert filter * refactor: i18n SupportedLngs * feat: modifiy the expiration time point of table data cached at the date level --- .eslintrc.js | 9 ++ src/App.tsx | 2 - src/__tests__/utils/date.test.ts | 10 --- .../Header/BlockchainComp/index.tsx | 21 +---- src/components/Sheet/index.tsx | 15 ++-- src/constants/cache.ts | 36 -------- src/constants/common.ts | 3 + src/contexts/providers/hook.ts | 19 ----- .../Home/AverageBlockTimeChart/index.tsx | 4 +- src/pages/Home/HashRateChart/index.tsx | 4 +- src/pages/Home/index.tsx | 14 +--- .../activities/AddressBalanceRank.tsx | 3 +- .../activities/AddressCount.tsx | 3 +- .../activities/BalanceDistribution.tsx | 7 +- .../StatisticsChart/activities/CellCount.tsx | 7 +- .../activities/TransactionCount.tsx | 3 +- .../activities/TxFeeHistory.tsx | 3 +- .../block/AverageBlockTime.tsx | 5 +- .../block/BlockTimeDistribution.tsx | 3 +- .../block/EpochTimeDistribution.tsx | 3 +- .../StatisticsChart/mining/Difficulty.tsx | 3 +- .../mining/DifficultyHashRate.tsx | 3 +- .../mining/DifficultyUncleRateEpoch.tsx | 7 +- src/pages/StatisticsChart/mining/HashRate.tsx | 5 +- .../mining/MinerAddressDistribution.tsx | 3 +- .../mining/MinerVersionDistribution.tsx | 3 +- .../StatisticsChart/mining/UncleRate.tsx | 3 +- .../monetary/AnnualPercentageCompensation.tsx | 3 +- .../monetary/InflationRate.tsx | 3 +- .../StatisticsChart/monetary/Liquidity.tsx | 3 +- .../monetary/SecondaryIssuance.tsx | 7 +- .../StatisticsChart/monetary/TotalSupply.tsx | 7 +- .../nervosDao/CirculationRatio.tsx | 3 +- .../nervosDao/NewDaoDeposit.tsx | 7 +- .../nervosDao/TotalDaoDeposit.tsx | 7 +- .../Transaction/TransactionCellList/index.tsx | 19 ++--- .../TransactionComp/TransactionComp.tsx | 24 +----- src/service/app/blockchain.ts | 15 ---- src/service/app/charts/cache.ts | 16 ---- src/services/AppSettings/hooks.ts | 29 +++++++ src/services/AppSettings/index.ts | 41 ++++++++++ src/services/CacheService/index.ts | 82 +++++++++++++++++++ src/services/ExplorerService/hooks.ts | 8 ++ src/services/ExplorerService/index.ts | 40 ++++++++- src/services/ExplorerService/requester.ts | 8 +- src/services/PersistenceService/index.ts | 66 +++++++++++++++ src/utils/cache.ts | 75 ----------------- src/utils/date.ts | 9 +- src/utils/hook.ts | 63 +++++++------- src/utils/i18n.ts | 20 +++-- src/utils/typescript.ts | 11 +++ 51 files changed, 402 insertions(+), 365 deletions(-) delete mode 100644 src/constants/cache.ts delete mode 100644 src/contexts/providers/hook.ts delete mode 100644 src/service/app/blockchain.ts delete mode 100644 src/service/app/charts/cache.ts create mode 100644 src/services/AppSettings/hooks.ts create mode 100644 src/services/AppSettings/index.ts create mode 100644 src/services/CacheService/index.ts create mode 100644 src/services/PersistenceService/index.ts delete mode 100644 src/utils/cache.ts create mode 100644 src/utils/typescript.ts diff --git a/.eslintrc.js b/.eslintrc.js index 447fd234e..62438f170 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,4 +1,5 @@ module.exports = { + root: true, extends: ['airbnb', 'plugin:prettier/recommended'], parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint', 'react-hooks', 'unused-imports'], @@ -99,7 +100,15 @@ module.exports = { allow: ['^.*_'], }, ], + // The service layer uses the singleton pattern, so there will be many methods that do not use this. + 'class-methods-use-this': 'off', + // TODO: Perhaps @typescript-eslint/recommended should be used. '@typescript-eslint/array-type': 'error', + 'no-dupe-class-members': 'off', + '@typescript-eslint/no-dupe-class-members': 'error', + 'lines-between-class-members': 'off', + // It looks like this rule has a bug, and it seems that typescript-eslint missed this rule when supporting eslint v8. + '@typescript-eslint/lines-between-class-members': 'off', }, env: { jest: true, diff --git a/src/App.tsx b/src/App.tsx index 07cfd7290..234d60573 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,7 +3,6 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { DefaultTheme, ThemeProvider } from 'styled-components' import Routers from './routes' import Toast from './components/Toast' -import useInitApp from './contexts/providers/hook' import { isMainnet } from './utils/chain' import { DASQueryContextProvider } from './contexts/providers/dasQuery' import { getPrimaryColor, getSecondaryColor } from './constants/common' @@ -17,7 +16,6 @@ const appStyle = { const queryClient = new QueryClient() const App = () => { - useInitApp() const theme = useMemo( () => ({ primary: getPrimaryColor(), diff --git a/src/__tests__/utils/date.test.ts b/src/__tests__/utils/date.test.ts index d98ea36a3..5726951a9 100644 --- a/src/__tests__/utils/date.test.ts +++ b/src/__tests__/utils/date.test.ts @@ -11,7 +11,6 @@ import { parseSimpleDate, parseSimpleDateNoSecond, getCurrentYear, - getCSTTime, } from '../../utils/date' describe('Date methods tests', () => { @@ -81,13 +80,4 @@ describe('Date methods tests', () => { MockDate.set(1588694400000) expect(getCurrentYear()).toBe(2020) }) - - it('getCSTTime', async () => { - timezoneMock.register('UTC') - expect(parseSimpleDate(1588651000000)).toBe('2020/05/05 03:56:40') - MockDate.set(1588651000000, 0) - expect(getCSTTime()).toBe(1588679800000) - timezoneMock.register('UTC') - expect(parseSimpleDate(1588679800000)).toBe('2020/05/05 11:56:40') - }) }) diff --git a/src/components/Header/BlockchainComp/index.tsx b/src/components/Header/BlockchainComp/index.tsx index ab9f56812..7a6d3d069 100644 --- a/src/components/Header/BlockchainComp/index.tsx +++ b/src/components/Header/BlockchainComp/index.tsx @@ -8,10 +8,9 @@ import { HeaderBlockchainPanel, MobileSubMenuPanel } from './styled' import SimpleButton from '../../SimpleButton' import ChainDropdown from '../../Dropdown/ChainType' import { useIsMobile } from '../../../utils/hook' -import { ChainName, MAINNET_URL, TESTNET_URL } from '../../../constants/common' +import { ChainName, MAINNET_URL, ONE_DAY_MILLISECOND, TESTNET_URL } from '../../../constants/common' import { explorerService } from '../../../services/ExplorerService' -import { AppCachedKeys } from '../../../constants/cache' -import { fetchCachedData, storeCachedData } from '../../../utils/cache' +import { cacheService } from '../../../services/CacheService' const getDropdownIcon = (showDropdown: boolean) => { if (!showDropdown) return WhiteDropdownIcon @@ -123,24 +122,12 @@ export default memo(() => { ['node_version'], async () => { const { version } = await explorerService.api.fetchNodeVersion() - storeCachedData(AppCachedKeys.Version, `${version}&${new Date().getTime()}`) + cacheService.set('node_version', version, { expireTime: ONE_DAY_MILLISECOND }) return version }, { keepPreviousData: true, - initialData: () => { - // version cache format: version×tamp - const data = fetchCachedData(AppCachedKeys.Version) - if (!data?.includes('&')) return undefined - - const timestamp = Number(data.substring(data.indexOf('&') + 1)) - const DAY_TIMESTAMP = 24 * 60 * 60 * 1000 - const isStale = Date.now() - timestamp > DAY_TIMESTAMP - if (isStale) return undefined - - const nodeVersion = data.substring(0, data.indexOf('&')) - return nodeVersion - }, + initialData: () => cacheService.get('node_version'), }, ) const nodeVersion = query.data ?? '' diff --git a/src/components/Sheet/index.tsx b/src/components/Sheet/index.tsx index ef24153dd..3644a61a2 100644 --- a/src/components/Sheet/index.tsx +++ b/src/components/Sheet/index.tsx @@ -1,18 +1,13 @@ import { useTranslation } from 'react-i18next' +import { useMemo } from 'react' import { SheetPanel, SheetPointPanel, SheetItem } from './styled' -import { createGlobalState, createGlobalStateSetter, useGlobalState } from '../../utils/state' - -const globalNetworkErrMsgs = createGlobalState([]) -const globalChainAlerts = createGlobalState([]) - -export const setNetworkErrMsgs = createGlobalStateSetter(globalNetworkErrMsgs) -export const setChainAlerts = createGlobalStateSetter(globalChainAlerts) +import { useBlockchainAlerts, useNetworkErrMsgs } from '../../services/ExplorerService' const Sheet = () => { const { t } = useTranslation() - const [networkErrMsgs] = useGlobalState(globalNetworkErrMsgs) - const [chainAlerts] = useGlobalState(globalChainAlerts) - const messages: string[] = chainAlerts.concat(networkErrMsgs) + const networkErrMsgs = useNetworkErrMsgs() + const chainAlerts = useBlockchainAlerts() + const messages = useMemo(() => [...chainAlerts, ...networkErrMsgs], [chainAlerts, networkErrMsgs]) return messages.length > 0 ? ( diff --git a/src/constants/cache.ts b/src/constants/cache.ts deleted file mode 100644 index aab0a6aa2..000000000 --- a/src/constants/cache.ts +++ /dev/null @@ -1,36 +0,0 @@ -import CONFIG from '../config' - -export const AppCachedKeys = { - AppLanguage: `${CONFIG.CHAIN_TYPE}-AppLanguage`, - Version: `${CONFIG.CHAIN_TYPE}-Version`, - NewAddrFormat: `is-address-format-new`, -} - -export const ChartCachedKeys = { - APC: `${CONFIG.CHAIN_TYPE}-APC`, - InflationRate: `${CONFIG.CHAIN_TYPE}-InflationRate`, - TransactionCount: `${CONFIG.CHAIN_TYPE}-TransactionCount`, - AddressCount: `${CONFIG.CHAIN_TYPE}-AddressCount`, - CellCount: `${CONFIG.CHAIN_TYPE}-CellCount`, - TransactionFee: `${CONFIG.CHAIN_TYPE}-TransactionFee`, - AddressBalanceRank: `${CONFIG.CHAIN_TYPE}-AddressBalanceRank`, - BalanceDistribution: `${CONFIG.CHAIN_TYPE}-BalanceDistribution`, - AverageBlockTime: `${CONFIG.CHAIN_TYPE}-AverageBlockTime`, - EpochTimeDistribution: `${CONFIG.CHAIN_TYPE}-EpochTimeDistribution`, - BlockTimeDistribution: `${CONFIG.CHAIN_TYPE}-BlockTimeDistribution`, - Difficulty: `${CONFIG.CHAIN_TYPE}-Difficulty`, - HashRate: `${CONFIG.CHAIN_TYPE}-HashRate`, - UncleRate: `${CONFIG.CHAIN_TYPE}-UncleRate`, - DifficultyHashRate: `${CONFIG.CHAIN_TYPE}-DifficultyHashRate`, - DifficultyUncleRateEpoch: `${CONFIG.CHAIN_TYPE}-DifficultyUncleRateEpoch`, - UncleHashRate: `${CONFIG.CHAIN_TYPE}-UncleHashRate`, - MinerAddressDistribution: `${CONFIG.CHAIN_TYPE}-MinerAddressDistribution`, - MinerVersionDistribution: `${CONFIG.CHAIN_TYPE}-MinerVersionDistribution`, - TotalDeposit: `${CONFIG.CHAIN_TYPE}-TotalDeposit`, - DailyDeposit: `${CONFIG.CHAIN_TYPE}-DailyDeposit`, - DepositCirculationRatio: `${CONFIG.CHAIN_TYPE}-DepositCirculationRatio`, - TotalSupply: `${CONFIG.CHAIN_TYPE}-TotalSupply`, - SecondaryIssuance: `${CONFIG.CHAIN_TYPE}-SecondaryIssuance`, - Liquidity: `${CONFIG.CHAIN_TYPE}-Liquidity`, - NodeDistribution: `${CONFIG.CHAIN_TYPE}-NodeDistribution`, -} diff --git a/src/constants/common.ts b/src/constants/common.ts index ba4292cbe..e6b5f6100 100644 --- a/src/constants/common.ts +++ b/src/constants/common.ts @@ -11,7 +11,10 @@ export const PAGE_CELL_COUNT = 200 export const NEXT_HARD_FORK_EPOCH = 5414 export const EPOCH_HOURS = 4 export const ONE_DAY_SECOND = 24 * 60 * 60 +export const ONE_DAY_MILLISECOND = ONE_DAY_SECOND * 1000 +export const ONE_YEAR_MILLISECOND = ONE_DAY_MILLISECOND * 365 export const ONE_HOUR_SECOND = 60 * 60 +export const ONE_HOUR_MILLISECOND = ONE_HOUR_SECOND * 1000 export const ONE_MINUTE_SECOND = 60 export const EPOCHS_PER_HALVING = 8760 export const THEORETICAL_EPOCH_TIME = 1000 * 60 * 60 * 4 // 4 hours diff --git a/src/contexts/providers/hook.ts b/src/contexts/providers/hook.ts deleted file mode 100644 index 24552a4a1..000000000 --- a/src/contexts/providers/hook.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { useState } from 'react' -import { FLUSH_CHART_CACHE_POLLING_TIME } from '../../constants/common' -import { useInterval } from '../../utils/hook' -import flushCacheInfo from '../../service/app/charts/cache' - -export const useInitApp = () => { - const [init, setInit] = useState(false) - - if (!init) { - setInit(true) - flushCacheInfo() - } - - useInterval(() => { - flushCacheInfo() - }, FLUSH_CHART_CACHE_POLLING_TIME) -} - -export default useInitApp diff --git a/src/pages/Home/AverageBlockTimeChart/index.tsx b/src/pages/Home/AverageBlockTimeChart/index.tsx index 10017f851..261c9899b 100644 --- a/src/pages/Home/AverageBlockTimeChart/index.tsx +++ b/src/pages/Home/AverageBlockTimeChart/index.tsx @@ -10,8 +10,8 @@ import { HomeChartLink, ChartLoadingPanel } from './styled' import ChartNoDataImage from '../../../assets/chart_no_data_white.png' import { useChartQueryWithCache, useIsLGScreen } from '../../../utils/hook' import { ChartItem, explorerService } from '../../../services/ExplorerService' -import { ChartCachedKeys } from '../../../constants/cache' import { ReactChartCore } from '../../StatisticsChart/common' +import { AverageBlockTimeCacheKey } from '../../StatisticsChart/block/AverageBlockTime' const useOption = () => { const { t } = useTranslation() @@ -111,7 +111,7 @@ export default memo(() => { const query = useChartQueryWithCache( explorerService.api.fetchStatisticAverageBlockTimes, - ChartCachedKeys.AverageBlockTime, + AverageBlockTimeCacheKey, 'date', ) const fullStatisticAverageBlockTimes = useMemo(() => query.data ?? [], [query.data]) diff --git a/src/pages/Home/HashRateChart/index.tsx b/src/pages/Home/HashRateChart/index.tsx index 5eafe6f2b..e67d068cd 100644 --- a/src/pages/Home/HashRateChart/index.tsx +++ b/src/pages/Home/HashRateChart/index.tsx @@ -11,8 +11,8 @@ import { HomeChartLink, ChartLoadingPanel } from './styled' import ChartNoDataImage from '../../../assets/chart_no_data_white.png' import { useChartQueryWithCache, useIsLGScreen } from '../../../utils/hook' import { ChartItem, explorerService } from '../../../services/ExplorerService' -import { ChartCachedKeys } from '../../../constants/cache' import { ReactChartCore } from '../../StatisticsChart/common' +import { HashRateCacheKey } from '../../StatisticsChart/mining/HashRate' const useOption = () => { const { t } = useTranslation() @@ -103,7 +103,7 @@ const useOption = () => { } export default memo(() => { const isLG = useIsLGScreen() - const query = useChartQueryWithCache(explorerService.api.fetchStatisticHashRate, ChartCachedKeys.HashRate, 'date') + const query = useChartQueryWithCache(explorerService.api.fetchStatisticHashRate, HashRateCacheKey, 'date') const fullStatisticHashRates = useMemo(() => query.data ?? [], [query.data]) const parseOption = useOption() diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx index 69a59d640..00e14ce74 100644 --- a/src/pages/Home/index.tsx +++ b/src/pages/Home/index.tsx @@ -14,12 +14,7 @@ import { } from './styled' import Content from '../../components/Content' import { parseTime, parseTimeNoSecond } from '../../utils/date' -import { - BLOCK_POLLING_TIME, - BLOCKCHAIN_ALERT_POLLING_TIME, - ListPageParams, - DELAY_BLOCK_NUMBER, -} from '../../constants/common' +import { BLOCK_POLLING_TIME, ListPageParams, DELAY_BLOCK_NUMBER } from '../../constants/common' import { localeNumberString, handleHashRate, handleDifficulty } from '../../utils/number' import { handleBigNumber } from '../../utils/string' import { isMainnet } from '../../utils/chain' @@ -27,10 +22,9 @@ import LatestBlocksIcon from '../../assets/latest_blocks.png' import LatestTransactionsIcon from '../../assets/latest_transactions.png' import { BlockCardItem, TransactionCardItem } from './TableCard' import Loading from '../../components/Loading/SmallLoading' -import { useElementIntersecting, useInterval, useIsLGScreen, useIsMobile } from '../../utils/hook' +import { useElementIntersecting, useIsLGScreen, useIsMobile } from '../../utils/hook' import Banner from '../../components/Banner' import { HalvingBanner } from '../../components/Banner/HalvingBanner' -import { handleBlockchainAlert } from '../../service/app/blockchain' import Search from '../../components/Search' import AverageBlockTimeChart from './AverageBlockTimeChart' import HashRateChart from './HashRateChart' @@ -233,10 +227,6 @@ export default () => { [transactionsQuery.data?.transactions], ) - useInterval(() => { - handleBlockchainAlert() - }, BLOCKCHAIN_ALERT_POLLING_TIME) - const blockchainDataList = useBlockchainDataList(isMobile, isLG) return ( diff --git a/src/pages/StatisticsChart/activities/AddressBalanceRank.tsx b/src/pages/StatisticsChart/activities/AddressBalanceRank.tsx index 619c4de9f..c50ce3647 100644 --- a/src/pages/StatisticsChart/activities/AddressBalanceRank.tsx +++ b/src/pages/StatisticsChart/activities/AddressBalanceRank.tsx @@ -7,7 +7,6 @@ import { shannonToCkb, shannonToCkbDecimal } from '../../../utils/util' import { localeNumberString } from '../../../utils/number' import { tooltipColor, tooltipWidth, SmartChartPage, SmartChartPageProps } from '../common' import { ChartItem, explorerService } from '../../../services/ExplorerService' -import { ChartCachedKeys } from '../../../constants/cache' import { useAdaptPCEllipsis } from '../../../utils/hook' import { ChartColorConfig } from '../../../constants/common' @@ -144,7 +143,7 @@ export const AddressBalanceRankChart = ({ isThumbnail = false }: { isThumbnail?: onFetched={setStatisticAddressBalanceRanks} getEChartOption={getEChartOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.AddressBalanceRank} + cacheKey="AddressBalanceRank" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/activities/AddressCount.tsx b/src/pages/StatisticsChart/activities/AddressCount.tsx index 66b0af4f7..31e0393d2 100644 --- a/src/pages/StatisticsChart/activities/AddressCount.tsx +++ b/src/pages/StatisticsChart/activities/AddressCount.tsx @@ -4,7 +4,6 @@ import { DATA_ZOOM_CONFIG, assertIsArray, handleAxis } from '../../../utils/char import { parseDateNoTime } from '../../../utils/date' import { tooltipColor, tooltipWidth, SmartChartPage } from '../common' import { ChartItem, explorerService } from '../../../services/ExplorerService' -import { ChartCachedKeys } from '../../../constants/cache' import { useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' @@ -109,7 +108,7 @@ export const AddressCountChart = ({ isThumbnail = false }: { isThumbnail?: boole fetchData={explorerService.api.fetchStatisticAddressCount} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.AddressCount} + cacheKey="AddressCount" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/activities/BalanceDistribution.tsx b/src/pages/StatisticsChart/activities/BalanceDistribution.tsx index 9702553d7..a003f2a47 100644 --- a/src/pages/StatisticsChart/activities/BalanceDistribution.tsx +++ b/src/pages/StatisticsChart/activities/BalanceDistribution.tsx @@ -1,6 +1,6 @@ import BigNumber from 'bignumber.js' import { useTranslation } from 'react-i18next' -import { LanuageType, useCurrentLanguage } from '../../../utils/i18n' +import { SupportedLng, useCurrentLanguage } from '../../../utils/i18n' import { DATA_ZOOM_CONFIG, assertIsArray, @@ -11,7 +11,6 @@ import { } from '../../../utils/chart' import { tooltipColor, tooltipWidth, SeriesItem, SmartChartPage } from '../common' import { localeNumberString } from '../../../utils/number' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { ChartColorConfig } from '../../../constants/common' @@ -22,7 +21,7 @@ const parseTooltip = ({ data, color, currentLanguage, -}: SeriesItem & { data: string; currentLanguage: LanuageType }): string => { +}: SeriesItem & { data: string; currentLanguage: SupportedLng }): string => { return `
${tooltipColor(color)}${widthSpan(seriesName, currentLanguage)} ${localeNumberString(data)}
` } @@ -188,7 +187,7 @@ export const BalanceDistributionChart = ({ isThumbnail = false }: { isThumbnail? fetchData={explorerService.api.fetchStatisticBalanceDistribution} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.BalanceDistribution} + cacheKey="BalanceDistribution" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/activities/CellCount.tsx b/src/pages/StatisticsChart/activities/CellCount.tsx index 0af7b0e08..d65638888 100644 --- a/src/pages/StatisticsChart/activities/CellCount.tsx +++ b/src/pages/StatisticsChart/activities/CellCount.tsx @@ -1,6 +1,6 @@ import BigNumber from 'bignumber.js' import { useTranslation } from 'react-i18next' -import { LanuageType, useCurrentLanguage } from '../../../utils/i18n' +import { SupportedLng, useCurrentLanguage } from '../../../utils/i18n' import { DATA_ZOOM_CONFIG, assertIsArray, @@ -10,11 +10,10 @@ import { } from '../../../utils/chart' import { parseDateNoTime } from '../../../utils/date' import { tooltipColor, tooltipWidth, SeriesItem, SmartChartPage } from '../common' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { ChartColorConfig } from '../../../constants/common' -const widthSpan = (value: string, currentLanguage: LanuageType) => +const widthSpan = (value: string, currentLanguage: SupportedLng) => tooltipWidth(value, currentLanguage === 'en' ? 125 : 80) const useTooltip = () => { @@ -195,7 +194,7 @@ export const CellCountChart = ({ isThumbnail = false }: { isThumbnail?: boolean fetchData={explorerService.api.fetchStatisticCellCount} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.CellCount} + cacheKey="CellCount" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/activities/TransactionCount.tsx b/src/pages/StatisticsChart/activities/TransactionCount.tsx index d2dc639ac..f85e99713 100644 --- a/src/pages/StatisticsChart/activities/TransactionCount.tsx +++ b/src/pages/StatisticsChart/activities/TransactionCount.tsx @@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next' import { DATA_ZOOM_CONFIG, assertIsArray, handleAxis } from '../../../utils/chart' import { parseDateNoTime } from '../../../utils/date' import { tooltipColor, tooltipWidth, SmartChartPage } from '../common' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' @@ -107,7 +106,7 @@ export const TransactionCountChart = ({ isThumbnail = false }: { isThumbnail?: b fetchData={explorerService.api.fetchStatisticTransactionCount} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.TransactionCount} + cacheKey="TransactionCount" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/activities/TxFeeHistory.tsx b/src/pages/StatisticsChart/activities/TxFeeHistory.tsx index bc57c545b..aa7edaddd 100644 --- a/src/pages/StatisticsChart/activities/TxFeeHistory.tsx +++ b/src/pages/StatisticsChart/activities/TxFeeHistory.tsx @@ -5,7 +5,6 @@ import { parseDateNoTime } from '../../../utils/date' import { tooltipColor, tooltipWidth, SmartChartPage } from '../common' import { shannonToCkbDecimal } from '../../../utils/util' import { isMainnet } from '../../../utils/chain' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' @@ -113,7 +112,7 @@ export const TxFeeHistoryChart = ({ isThumbnail = false }: { isThumbnail?: boole fetchData={explorerService.api.fetchStatisticTxFeeHistory} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.TransactionFee} + cacheKey="TransactionFee" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/block/AverageBlockTime.tsx b/src/pages/StatisticsChart/block/AverageBlockTime.tsx index 91cbca489..3d426f81e 100644 --- a/src/pages/StatisticsChart/block/AverageBlockTime.tsx +++ b/src/pages/StatisticsChart/block/AverageBlockTime.tsx @@ -4,10 +4,11 @@ import { tooltipColor, tooltipWidth, SeriesItem, SmartChartPage } from '../commo import { localeNumberString } from '../../../utils/number' import { DATA_ZOOM_CONFIG, assertIsArray, assertSerialsDataIsString, assertSerialsItem } from '../../../utils/chart' import { ChartItem, explorerService } from '../../../services/ExplorerService' -import { ChartCachedKeys } from '../../../constants/cache' import { useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' +export const AverageBlockTimeCacheKey = 'AverageBlockTime' + const useOption = ( statisticAverageBlockTimes: ChartItem.AverageBlockTime[], chartColor: ChartColorConfig, @@ -194,7 +195,7 @@ export const AverageBlockTimeChart = ({ isThumbnail = false }: { isThumbnail?: b fetchData={explorerService.api.fetchStatisticAverageBlockTimes} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.AverageBlockTime} + cacheKey={AverageBlockTimeCacheKey} cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/block/BlockTimeDistribution.tsx b/src/pages/StatisticsChart/block/BlockTimeDistribution.tsx index bb8ee2a11..f017e0648 100644 --- a/src/pages/StatisticsChart/block/BlockTimeDistribution.tsx +++ b/src/pages/StatisticsChart/block/BlockTimeDistribution.tsx @@ -1,7 +1,6 @@ import { useTranslation } from 'react-i18next' import { DATA_ZOOM_CONFIG, assertIsArray } from '../../../utils/chart' import { tooltipColor, tooltipWidth, SmartChartPage } from '../common' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' @@ -105,7 +104,7 @@ export const BlockTimeDistributionChart = ({ isThumbnail = false }: { isThumbnai fetchData={explorerService.api.fetchStatisticBlockTimeDistribution} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.BlockTimeDistribution} + cacheKey="BlockTimeDistribution" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/block/EpochTimeDistribution.tsx b/src/pages/StatisticsChart/block/EpochTimeDistribution.tsx index ed3f85cea..d51c8afcf 100644 --- a/src/pages/StatisticsChart/block/EpochTimeDistribution.tsx +++ b/src/pages/StatisticsChart/block/EpochTimeDistribution.tsx @@ -4,7 +4,6 @@ import { localeNumberString } from '../../../utils/number' import { parseHourFromMinute } from '../../../utils/date' import { DATA_ZOOM_CONFIG, assertIsArray } from '../../../utils/chart' import { ChartItem, explorerService } from '../../../services/ExplorerService' -import { ChartCachedKeys } from '../../../constants/cache' import { useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' @@ -112,7 +111,7 @@ export const EpochTimeDistributionChart = ({ isThumbnail = false }: { isThumbnai fetchData={explorerService.api.fetchStatisticEpochTimeDistribution} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.EpochTimeDistribution} + cacheKey="EpochTimeDistribution" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/mining/Difficulty.tsx b/src/pages/StatisticsChart/mining/Difficulty.tsx index 894e64ee8..da7890285 100644 --- a/src/pages/StatisticsChart/mining/Difficulty.tsx +++ b/src/pages/StatisticsChart/mining/Difficulty.tsx @@ -4,7 +4,6 @@ import { DATA_ZOOM_CONFIG, assertIsArray, handleAxis } from '../../../utils/char import { parseDateNoTime } from '../../../utils/date' import { handleDifficulty } from '../../../utils/number' import { tooltipColor, tooltipWidth, SmartChartPage } from '../common' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' @@ -109,7 +108,7 @@ export const DifficultyChart = ({ isThumbnail = false }: { isThumbnail?: boolean fetchData={explorerService.api.fetchStatisticDifficulty} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.Difficulty} + cacheKey="Difficulty" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/mining/DifficultyHashRate.tsx b/src/pages/StatisticsChart/mining/DifficultyHashRate.tsx index f6575158d..40f8532ac 100644 --- a/src/pages/StatisticsChart/mining/DifficultyHashRate.tsx +++ b/src/pages/StatisticsChart/mining/DifficultyHashRate.tsx @@ -10,7 +10,6 @@ import { import { handleDifficulty, handleHashRate } from '../../../utils/number' import { tooltipColor, tooltipWidth, SeriesItem, SmartChartPage } from '../common' import { ChartItem, explorerService } from '../../../services/ExplorerService' -import { ChartCachedKeys } from '../../../constants/cache' import { useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' @@ -202,7 +201,7 @@ export const DifficultyHashRateChart = ({ isThumbnail = false }: { isThumbnail?: fetchData={explorerService.api.fetchStatisticDifficultyHashRate} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.DifficultyHashRate} + cacheKey="DifficultyHashRate" cacheMode="epoch" /> ) diff --git a/src/pages/StatisticsChart/mining/DifficultyUncleRateEpoch.tsx b/src/pages/StatisticsChart/mining/DifficultyUncleRateEpoch.tsx index 5e842b1a6..bd7be7eab 100644 --- a/src/pages/StatisticsChart/mining/DifficultyUncleRateEpoch.tsx +++ b/src/pages/StatisticsChart/mining/DifficultyUncleRateEpoch.tsx @@ -4,12 +4,11 @@ import { useTranslation } from 'react-i18next' import { assertSerialsDataIsString, assertIsArray, assertSerialsItem, handleAxis } from '../../../utils/chart' import { tooltipColor, tooltipWidth, SeriesItem, SmartChartPage } from '../common' import { parseHourFromMillisecond } from '../../../utils/date' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' -import { LanuageType, useCurrentLanguage } from '../../../utils/i18n' +import { SupportedLng, useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' -const widthSpan = (value: string, currentLanguage: LanuageType) => +const widthSpan = (value: string, currentLanguage: SupportedLng) => tooltipWidth(value, currentLanguage === 'en' ? 90 : 80) const useTooltip = () => { @@ -217,7 +216,7 @@ export const DifficultyUncleRateEpochChart: FC<{ isThumbnail?: boolean }> = ({ i fetchData={explorerService.api.fetchStatisticDifficultyUncleRateEpoch} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.DifficultyUncleRateEpoch} + cacheKey="DifficultyUncleRateEpoch" cacheMode="epoch" /> ) diff --git a/src/pages/StatisticsChart/mining/HashRate.tsx b/src/pages/StatisticsChart/mining/HashRate.tsx index 19d0d367f..a0b6d2930 100644 --- a/src/pages/StatisticsChart/mining/HashRate.tsx +++ b/src/pages/StatisticsChart/mining/HashRate.tsx @@ -5,10 +5,11 @@ import { parseDateNoTime } from '../../../utils/date' import { handleHashRate } from '../../../utils/number' import { tooltipColor, tooltipWidth, SmartChartPage } from '../common' import { ChartItem, explorerService } from '../../../services/ExplorerService' -import { ChartCachedKeys } from '../../../constants/cache' import { useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' +export const HashRateCacheKey = 'HashRate' + const useOption = ( statisticHashRates: ChartItem.HashRate[], chartColor: ChartColorConfig, @@ -108,7 +109,7 @@ export const HashRateChart = ({ isThumbnail = false }: { isThumbnail?: boolean } fetchData={explorerService.api.fetchStatisticHashRate} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.HashRate} + cacheKey={HashRateCacheKey} cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/mining/MinerAddressDistribution.tsx b/src/pages/StatisticsChart/mining/MinerAddressDistribution.tsx index f667d4d49..ce6e70499 100644 --- a/src/pages/StatisticsChart/mining/MinerAddressDistribution.tsx +++ b/src/pages/StatisticsChart/mining/MinerAddressDistribution.tsx @@ -2,7 +2,6 @@ import { useCallback } from 'react' import { useHistory } from 'react-router' import { useTranslation } from 'react-i18next' import { tooltipColor, tooltipWidth, SmartChartPage, SmartChartPageProps } from '../common' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { useAdaptMobileEllipsis, useAdaptPCEllipsis, useIsMobile } from '../../../utils/hook' import { useCurrentLanguage } from '../../../utils/i18n' @@ -123,7 +122,7 @@ export const MinerAddressDistributionChart = ({ isThumbnail = false }: { isThumb fetchData={explorerService.api.fetchStatisticMinerAddressDistribution} getEChartOption={getEChartOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.MinerAddressDistribution} + cacheKey="MinerAddressDistribution" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/mining/MinerVersionDistribution.tsx b/src/pages/StatisticsChart/mining/MinerVersionDistribution.tsx index b49b00cbe..c0e012016 100644 --- a/src/pages/StatisticsChart/mining/MinerVersionDistribution.tsx +++ b/src/pages/StatisticsChart/mining/MinerVersionDistribution.tsx @@ -1,7 +1,6 @@ import { useTranslation } from 'react-i18next' import { EChartOption } from 'echarts' import { tooltipColor, tooltipWidth, SmartChartPage } from '../common' -import { ChartCachedKeys } from '../../../constants/cache' import { explorerService } from '../../../services/ExplorerService' import { useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' @@ -122,7 +121,7 @@ export const MinerVersionDistributionChart = ({ isThumbnail = false }: { isThumb fetchData={fetchData} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.MinerVersionDistribution} + cacheKey="MinerVersionDistribution" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/mining/UncleRate.tsx b/src/pages/StatisticsChart/mining/UncleRate.tsx index 384910617..8241f77dc 100644 --- a/src/pages/StatisticsChart/mining/UncleRate.tsx +++ b/src/pages/StatisticsChart/mining/UncleRate.tsx @@ -3,7 +3,6 @@ import { parseDateNoTime } from '../../../utils/date' import { tooltipColor, tooltipWidth, SmartChartPage } from '../common' import { DATA_ZOOM_CONFIG, assertIsArray } from '../../../utils/chart' import { ChartItem, explorerService } from '../../../services/ExplorerService' -import { ChartCachedKeys } from '../../../constants/cache' import { useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' @@ -124,7 +123,7 @@ export const UncleRateChart = ({ isThumbnail = false }: { isThumbnail?: boolean fetchData={explorerService.api.fetchStatisticUncleRate} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.UncleRate} + cacheKey="UncleRate" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/monetary/AnnualPercentageCompensation.tsx b/src/pages/StatisticsChart/monetary/AnnualPercentageCompensation.tsx index 2a86d93d2..c74ac19b7 100644 --- a/src/pages/StatisticsChart/monetary/AnnualPercentageCompensation.tsx +++ b/src/pages/StatisticsChart/monetary/AnnualPercentageCompensation.tsx @@ -2,7 +2,6 @@ import { useTranslation } from 'react-i18next' import { useCurrentLanguage } from '../../../utils/i18n' import { tooltipColor, tooltipWidth, SmartChartPage } from '../common' import { DATA_ZOOM_CONFIG, assertIsArray } from '../../../utils/chart' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { ChartColorConfig } from '../../../constants/common' @@ -109,7 +108,7 @@ export const AnnualPercentageCompensationChart = ({ isThumbnail = false }: { isT fetchData={explorerService.api.fetchStatisticAnnualPercentageCompensation} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.APC} + cacheKey="APC" cacheMode="forever" /> ) diff --git a/src/pages/StatisticsChart/monetary/InflationRate.tsx b/src/pages/StatisticsChart/monetary/InflationRate.tsx index 8e60d1a4f..ca1266fc4 100644 --- a/src/pages/StatisticsChart/monetary/InflationRate.tsx +++ b/src/pages/StatisticsChart/monetary/InflationRate.tsx @@ -2,7 +2,6 @@ import { useTranslation } from 'react-i18next' import { useCurrentLanguage } from '../../../utils/i18n' import { tooltipColor, tooltipWidth, SeriesItem, SmartChartPage } from '../common' import { DATA_ZOOM_CONFIG, assertSerialsDataIsString, assertIsArray, assertSerialsItem } from '../../../utils/chart' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { ChartColorConfig } from '../../../constants/common' @@ -168,7 +167,7 @@ export const InflationRateChart = ({ isThumbnail = false }: { isThumbnail?: bool fetchData={explorerService.api.fetchStatisticInflationRate} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.InflationRate} + cacheKey="InflationRate" cacheMode="forever" /> ) diff --git a/src/pages/StatisticsChart/monetary/Liquidity.tsx b/src/pages/StatisticsChart/monetary/Liquidity.tsx index c282efb05..e10e59925 100644 --- a/src/pages/StatisticsChart/monetary/Liquidity.tsx +++ b/src/pages/StatisticsChart/monetary/Liquidity.tsx @@ -10,7 +10,6 @@ import { parseNumericAbbr, } from '../../../utils/chart' import { shannonToCkb, shannonToCkbDecimal } from '../../../utils/util' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { ChartColorConfig } from '../../../constants/common' @@ -198,7 +197,7 @@ export const LiquidityChart = ({ isThumbnail = false }: { isThumbnail?: boolean fetchData={explorerService.api.fetchStatisticLiquidity} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.Liquidity} + cacheKey="Liquidity" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/monetary/SecondaryIssuance.tsx b/src/pages/StatisticsChart/monetary/SecondaryIssuance.tsx index 2915579ee..08b489ca1 100644 --- a/src/pages/StatisticsChart/monetary/SecondaryIssuance.tsx +++ b/src/pages/StatisticsChart/monetary/SecondaryIssuance.tsx @@ -1,5 +1,5 @@ import { useTranslation } from 'react-i18next' -import { LanuageType, useCurrentLanguage } from '../../../utils/i18n' +import { SupportedLng, useCurrentLanguage } from '../../../utils/i18n' import { parseDateNoTime } from '../../../utils/date' import { tooltipColor, tooltipWidth, SeriesItem, SmartChartPage } from '../common' import { @@ -8,11 +8,10 @@ import { assertSerialsDataIsStringArrayOf4, assertSerialsItem, } from '../../../utils/chart' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { ChartColorConfig } from '../../../constants/common' -const widthSpan = (value: string, currentLanguage: LanuageType) => +const widthSpan = (value: string, currentLanguage: SupportedLng) => tooltipWidth(value, currentLanguage === 'en' ? 155 : 70) const useTooltip = () => { @@ -192,7 +191,7 @@ export const SecondaryIssuanceChart = ({ isThumbnail = false }: { isThumbnail?: fetchData={explorerService.api.fetchStatisticSecondaryIssuance} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.SecondaryIssuance} + cacheKey="SecondaryIssuance" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/monetary/TotalSupply.tsx b/src/pages/StatisticsChart/monetary/TotalSupply.tsx index 16a6adb72..344600b62 100644 --- a/src/pages/StatisticsChart/monetary/TotalSupply.tsx +++ b/src/pages/StatisticsChart/monetary/TotalSupply.tsx @@ -1,6 +1,6 @@ import BigNumber from 'bignumber.js' import { useTranslation } from 'react-i18next' -import { LanuageType, useCurrentLanguage } from '../../../utils/i18n' +import { SupportedLng, useCurrentLanguage } from '../../../utils/i18n' import { DATA_ZOOM_CONFIG, assertIsArray, @@ -11,11 +11,10 @@ import { import { parseDateNoTime } from '../../../utils/date' import { tooltipColor, tooltipWidth, SeriesItem, SmartChartPage } from '../common' import { shannonToCkb, shannonToCkbDecimal } from '../../../utils/util' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { ChartColorConfig } from '../../../constants/common' -const widthSpan = (value: string, currentLanguage: LanuageType) => +const widthSpan = (value: string, currentLanguage: SupportedLng) => tooltipWidth(value, currentLanguage === 'en' ? 125 : 80) const useTooltip = () => { @@ -208,7 +207,7 @@ export const TotalSupplyChart = ({ isThumbnail = false }: { isThumbnail?: boolea fetchData={explorerService.api.fetchStatisticTotalSupply} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.TotalSupply} + cacheKey="TotalSupply" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/nervosDao/CirculationRatio.tsx b/src/pages/StatisticsChart/nervosDao/CirculationRatio.tsx index a423ee114..50920129f 100644 --- a/src/pages/StatisticsChart/nervosDao/CirculationRatio.tsx +++ b/src/pages/StatisticsChart/nervosDao/CirculationRatio.tsx @@ -3,7 +3,6 @@ import { useCurrentLanguage } from '../../../utils/i18n' import { parseDateNoTime } from '../../../utils/date' import { tooltipColor, tooltipWidth, SmartChartPage } from '../common' import { DATA_ZOOM_CONFIG, assertIsArray } from '../../../utils/chart' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { ChartColorConfig } from '../../../constants/common' @@ -110,7 +109,7 @@ export const CirculationRatioChart = ({ isThumbnail = false }: { isThumbnail?: b fetchData={explorerService.api.fetchStatisticCirculationRatio} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.DepositCirculationRatio} + cacheKey="DepositCirculationRatio" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/nervosDao/NewDaoDeposit.tsx b/src/pages/StatisticsChart/nervosDao/NewDaoDeposit.tsx index b07a3e15d..8d908acae 100644 --- a/src/pages/StatisticsChart/nervosDao/NewDaoDeposit.tsx +++ b/src/pages/StatisticsChart/nervosDao/NewDaoDeposit.tsx @@ -1,6 +1,6 @@ import BigNumber from 'bignumber.js' import { useTranslation } from 'react-i18next' -import { LanuageType, useCurrentLanguage } from '../../../utils/i18n' +import { SupportedLng, useCurrentLanguage } from '../../../utils/i18n' import { DATA_ZOOM_CONFIG, assertIsArray, @@ -12,11 +12,10 @@ import { parseDateNoTime } from '../../../utils/date' import { shannonToCkb, shannonToCkbDecimal } from '../../../utils/util' import { isMainnet } from '../../../utils/chain' import { tooltipWidth, tooltipColor, SeriesItem, SmartChartPage } from '../common' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { ChartColorConfig } from '../../../constants/common' -const widthSpan = (value: string, language: LanuageType) => tooltipWidth(value, language === 'en' ? 140 : 120) +const widthSpan = (value: string, language: SupportedLng) => tooltipWidth(value, language === 'en' ? 140 : 120) const useTooltip = () => { const { t } = useTranslation() @@ -197,7 +196,7 @@ export const NewDaoDepositChart = ({ isThumbnail = false }: { isThumbnail?: bool fetchData={explorerService.api.fetchStatisticNewDaoDeposit} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.DailyDeposit} + cacheKey="DailyDeposit" cacheMode="date" /> ) diff --git a/src/pages/StatisticsChart/nervosDao/TotalDaoDeposit.tsx b/src/pages/StatisticsChart/nervosDao/TotalDaoDeposit.tsx index 3ef3e21e8..641c92a17 100644 --- a/src/pages/StatisticsChart/nervosDao/TotalDaoDeposit.tsx +++ b/src/pages/StatisticsChart/nervosDao/TotalDaoDeposit.tsx @@ -1,6 +1,6 @@ import BigNumber from 'bignumber.js' import { useTranslation } from 'react-i18next' -import { LanuageType, useCurrentLanguage } from '../../../utils/i18n' +import { SupportedLng, useCurrentLanguage } from '../../../utils/i18n' import { DATA_ZOOM_CONFIG, assertIsArray, @@ -12,11 +12,10 @@ import { parseDateNoTime } from '../../../utils/date' import { shannonToCkb, shannonToCkbDecimal } from '../../../utils/util' import { isMainnet } from '../../../utils/chain' import { tooltipColor, tooltipWidth, SeriesItem, SmartChartPage } from '../common' -import { ChartCachedKeys } from '../../../constants/cache' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { ChartColorConfig } from '../../../constants/common' -const widthSpan = (value: string, language: LanuageType) => tooltipWidth(value, language === 'en' ? 168 : 110) +const widthSpan = (value: string, language: SupportedLng) => tooltipWidth(value, language === 'en' ? 168 : 110) const useTooltip = () => { const { t } = useTranslation() @@ -196,7 +195,7 @@ export const TotalDaoDepositChart = ({ isThumbnail = false }: { isThumbnail?: bo fetchData={explorerService.api.fetchStatisticTotalDaoDeposit} getEChartOption={useOption} toCSV={toCSV} - cacheKey={ChartCachedKeys.TotalDeposit} + cacheKey="TotalDeposit" cacheMode="date" /> ) diff --git a/src/pages/Transaction/TransactionCellList/index.tsx b/src/pages/Transaction/TransactionCellList/index.tsx index 943b1aac2..0a49a8243 100644 --- a/src/pages/Transaction/TransactionCellList/index.tsx +++ b/src/pages/Transaction/TransactionCellList/index.tsx @@ -10,6 +10,7 @@ import { ReactComponent as DeprecatedAddrOff } from '../../../assets/deprecated_ import { ReactComponent as Warning } from '../../../assets/warning.svg' import styles from './styles.module.scss' import { Cell } from '../../../models/Cell' +import { useIsDeprecatedAddressesDisplayed } from '../../../services/AppSettings/hooks' const SCROLL_BOTTOM_OFFSET = 5 const SCROLL_LOADING_TIME = 400 @@ -19,16 +20,11 @@ export default ({ outputs, txHash, showReward, - addrToggle: { isAddrNew, setIsAddrNew }, }: { inputs?: Cell[] outputs?: Cell[] txHash?: string showReward?: boolean - addrToggle: { - isAddrNew: boolean - setIsAddrNew: (is: boolean) => void - } }) => { const { t } = useTranslation() const [offset, setOffset] = useState(PAGE_CELL_COUNT) @@ -54,9 +50,8 @@ export default ({ [offset, cells.length], ) - const handleAddrToggle = () => { - setIsAddrNew(!isAddrNew) - } + const [isDeprecatedAddressesDisplayed, setIsDeprecatedAddressesDisplayed] = useIsDeprecatedAddressesDisplayed() + const toggleDeprecatedAddressesDisplayed = () => setIsDeprecatedAddressesDisplayed(value => !value) const cellsCount = () => { if (inputs) { @@ -71,11 +66,11 @@ export default ({
{`${title} (${cellsCount()})`} -
- {isAddrNew ? : } +
+ {!isDeprecatedAddressesDisplayed ? : }
- {isAddrNew ? null : ( + {!isDeprecatedAddressesDisplayed ? null : ( @@ -107,7 +102,7 @@ export default ({ index={index} txHash={txHash} showReward={showReward} - isAddrNew={isAddrNew} + isAddrNew={!isDeprecatedAddressesDisplayed} /> ))} {isScroll && !isEnd && } diff --git a/src/pages/Transaction/TransactionComp/TransactionComp.tsx b/src/pages/Transaction/TransactionComp/TransactionComp.tsx index d36f8dd1c..be98cacb8 100644 --- a/src/pages/Transaction/TransactionComp/TransactionComp.tsx +++ b/src/pages/Transaction/TransactionComp/TransactionComp.tsx @@ -1,5 +1,4 @@ import TransactionCellList from '../TransactionCellList' -import { useAddrFormatToggle } from '../../../utils/hook' import { Cell } from '../../../models/Cell' import { Transaction } from '../../../models/Transaction' @@ -21,35 +20,16 @@ const handleCellbaseInputs = (inputs: Cell[], outputs: Cell[]) => { export const TransactionComp = ({ transaction }: { transaction: Transaction }) => { const { transactionHash, displayInputs, displayOutputs, blockNumber, isCellbase } = transaction - const { isNew: isAddrNew, setIsNew: setIsAddrNew } = useAddrFormatToggle() const inputs = handleCellbaseInputs(displayInputs, displayOutputs) /// [0, 11] block doesn't show block reward and only cellbase show block reward return ( <>
- {inputs && ( - 0 && isCellbase} - addrToggle={{ - isAddrNew, - setIsAddrNew, - }} - /> - )} + {inputs && 0 && isCellbase} />}
- {displayOutputs && ( - - )} + {displayOutputs && }
) diff --git a/src/service/app/blockchain.ts b/src/service/app/blockchain.ts deleted file mode 100644 index 9fe77a350..000000000 --- a/src/service/app/blockchain.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { explorerService } from '../../services/ExplorerService' -import { setChainAlerts } from '../../components/Sheet' - -const ALERT_TO_FILTER_OUT = 'CKB v0.105.* have bugs. Please upgrade to the latest version.' - -export const handleBlockchainAlert = () => { - explorerService.api.fetchBlockchainInfo().then(wrapper => { - const alerts = wrapper?.attributes.blockchainInfo.alerts ?? [] - setChainAlerts(alerts.map(alert => alert.message).filter(msg => msg !== ALERT_TO_FILTER_OUT)) - }) -} - -export default { - handleBlockchainAlert, -} diff --git a/src/service/app/charts/cache.ts b/src/service/app/charts/cache.ts deleted file mode 100644 index 3a3402e49..000000000 --- a/src/service/app/charts/cache.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { explorerService } from '../../../services/ExplorerService' -import { removeCachedData, fetchCachedData } from '../../../utils/cache' -import { ChartCachedKeys } from '../../../constants/cache' - -export const flushCacheInfo = async () => { - const { flushCacheInfo } = await explorerService.api.fetchFlushChartCache() - if (flushCacheInfo.length === 0) return - - // eslint-disable-next-line no-restricted-syntax - for (const [, value] of Object.entries(ChartCachedKeys)) { - removeCachedData(fetchCachedData(value) as string) - removeCachedData(value) - } -} - -export default flushCacheInfo diff --git a/src/services/AppSettings/hooks.ts b/src/services/AppSettings/hooks.ts new file mode 100644 index 000000000..1868b3cb4 --- /dev/null +++ b/src/services/AppSettings/hooks.ts @@ -0,0 +1,29 @@ +import { useObservableState } from 'observable-hooks' +import { BehaviorSubject } from 'rxjs' +import { Dispatch, SetStateAction } from 'react' +import { appSettings } from '.' + +function createPropSetter(prop: BehaviorSubject): Dispatch> { + function isUpdater(value: unknown): value is (prevState: T) => T { + return typeof value === 'function' + } + + return (action: T | ((prevState: T) => T)) => { + if (isUpdater(action)) { + prop.next(action(prop.value)) + } else { + prop.next(action) + } + } +} + +export function useDefaultLanguage() { + return [useObservableState(appSettings.defaultLanguage$), createPropSetter(appSettings.defaultLanguage$)] as const +} + +export function useIsDeprecatedAddressesDisplayed() { + return [ + useObservableState(appSettings.isDeprecatedAddressesDisplayed$), + createPropSetter(appSettings.isDeprecatedAddressesDisplayed$), + ] as const +} diff --git a/src/services/AppSettings/index.ts b/src/services/AppSettings/index.ts new file mode 100644 index 000000000..5767bc854 --- /dev/null +++ b/src/services/AppSettings/index.ts @@ -0,0 +1,41 @@ +import { BehaviorSubject, Subscription, tap } from 'rxjs' +import { PersistenceService, persistenceService } from '../PersistenceService' +import CONFIG from '../../config' +import { SupportedLng } from '../../utils/i18n' + +export const NAMESPACE_APP_SETTINGS = 'appSettings' + +export const KEY_DEFAULT_LANGUAGE = `${CONFIG.CHAIN_TYPE}_${NAMESPACE_APP_SETTINGS}_defaultLanguage` +export const KEY_IS_DEPRECATED_ADDRESSES_DISPLAYED = `${NAMESPACE_APP_SETTINGS}_isDeprecatedAddressesDisplayed` + +export class AppSettings { + defaultLanguage$ = new BehaviorSubject(this.persistenceService.get(KEY_DEFAULT_LANGUAGE, 'en')) + + isDeprecatedAddressesDisplayed$ = new BehaviorSubject( + this.persistenceService.get(KEY_IS_DEPRECATED_ADDRESSES_DISPLAYED, false), + ) + + private callbacksAtStop?: Subscription + + constructor(private persistenceService: PersistenceService) { + this.start() + } + + start() { + this.callbacksAtStop?.unsubscribe() + this.callbacksAtStop = new Subscription() + + this.saveToStorageOnChange(this.defaultLanguage$, KEY_DEFAULT_LANGUAGE) + this.saveToStorageOnChange(this.isDeprecatedAddressesDisplayed$, KEY_IS_DEPRECATED_ADDRESSES_DISPLAYED) + } + + stop() { + this.callbacksAtStop?.unsubscribe() + } + + private saveToStorageOnChange(prop: BehaviorSubject, key: string) { + this.callbacksAtStop?.add(prop.pipe(tap(value => this.persistenceService.set(key, value))).subscribe()) + } +} + +export const appSettings = new AppSettings(persistenceService) diff --git a/src/services/CacheService/index.ts b/src/services/CacheService/index.ts new file mode 100644 index 000000000..9bfe1bb48 --- /dev/null +++ b/src/services/CacheService/index.ts @@ -0,0 +1,82 @@ +import { ONE_DAY_MILLISECOND } from '../../constants/common' +import CONFIG from '../../config' +import { PersistenceService, persistenceService } from '../PersistenceService' +import { MutexAttr } from '../../utils/typescript' + +export const NAMESPACE_CACHE = 'cache' + +type ExpireOptions = MutexAttr<{ expireTime?: number }, { expireAt?: Date | number }> + +type CacheOptions = ExpireOptions & { + /** + * The default value is false. If it is false, different cache keys will be created based on the current network type, + * so the data cached on the mainnet and testnet will be different. If it is true, all networks will use the same key and data. + */ + networkTypeAgnostic?: boolean +} + +export interface CacheData { + expireAt: number + data: T +} + +export class CacheService { + constructor(private persistenceService: PersistenceService) { + this.getAllKeys().forEach(key => this.removeIfExpired(key, this.persistenceService.get>(key))) + } + + get(key: string): T | undefined + get(key: string, defaultValue: T): T + get(key: string, defaultValue?: T): T | undefined { + const keyInChain = `${NAMESPACE_CACHE}_${CONFIG.CHAIN_TYPE}_${key}` + const cacheInChain = this.persistenceService.get>(keyInChain) + if (cacheInChain != null && !this.removeIfExpired(keyInChain, cacheInChain)) { + return cacheInChain.data + } + + const keyAllChain = `${NAMESPACE_CACHE}_${key}` + const cacheAllChain = this.persistenceService.get>(keyAllChain) + if (cacheAllChain != null && !this.removeIfExpired(keyAllChain, cacheAllChain)) { + return cacheAllChain.data + } + + return defaultValue + } + + set(key: string, value: T, opts: CacheOptions = {}): boolean { + const { expireTime = ONE_DAY_MILLISECOND * 7, expireAt, networkTypeAgnostic } = opts + + const keyPrefix = networkTypeAgnostic ? NAMESPACE_CACHE : `${NAMESPACE_CACHE}_${CONFIG.CHAIN_TYPE}` + const finalKey = `${keyPrefix}_${key}` + + try { + this.persistenceService.set>(finalKey, { + expireAt: expireAt instanceof Date ? expireAt.getTime() : expireAt ?? Date.now() + expireTime, + data: value, + }) + return true + } catch (err) { + // Cache failure is acceptable, just swallow the error. + // TODO: When there is not enough space, automatically remove old cache according to some rules. + return false + } + } + + getAllKeys() { + return this.persistenceService.getAllKeys().filter(key => key.startsWith(`${NAMESPACE_CACHE}_`)) + } + + clear() { + this.getAllKeys().forEach(key => this.persistenceService.remove(key)) + } + + removeIfExpired(key: string, cacheData: CacheData | undefined) { + if (cacheData == null) return true + if (cacheData.expireAt > Date.now()) return false + + this.persistenceService.remove(key) + return true + } +} + +export const cacheService = new CacheService(persistenceService) diff --git a/src/services/ExplorerService/hooks.ts b/src/services/ExplorerService/hooks.ts index 7eff9d9ab..53f3c6c80 100644 --- a/src/services/ExplorerService/hooks.ts +++ b/src/services/ExplorerService/hooks.ts @@ -8,3 +8,11 @@ export function useStatistics() { export function useLatestBlockNumber() { return useObservableState(explorerService.latestBlockNumber$) } + +export function useBlockchainAlerts() { + return useObservableState(explorerService.blockchainAlerts$) +} + +export function useNetworkErrMsgs() { + return useObservableState(explorerService.networkErrMsgs$) +} diff --git a/src/services/ExplorerService/index.ts b/src/services/ExplorerService/index.ts index f7dc39c8f..6a5e434ed 100644 --- a/src/services/ExplorerService/index.ts +++ b/src/services/ExplorerService/index.ts @@ -1,6 +1,12 @@ import { BehaviorSubject, Subscription, map, switchMap, timer } from 'rxjs' -import { BLOCK_POLLING_TIME } from '../../constants/common' +import { + BLOCKCHAIN_ALERT_POLLING_TIME, + BLOCK_POLLING_TIME, + FLUSH_CHART_CACHE_POLLING_TIME, +} from '../../constants/common' import { APIReturn, apiFetcher } from './fetcher' +import { networkErrMsgs$ } from './requester' +import { CacheService, cacheService } from '../CacheService' const initStatistics: APIReturn<'fetchStatistics'> = { tipBlockNumber: '0', @@ -32,14 +38,20 @@ class ExplorerService { // so another API is used here to obtain it separately. latestBlockNumber$ = new BehaviorSubject(0) + blockchainAlerts$ = new BehaviorSubject([]) + + networkErrMsgs$ = networkErrMsgs$ + private callbacksAtStop?: Subscription - constructor() { + constructor(private cacheService: CacheService) { this.start() } start() { + this.callbacksAtStop?.unsubscribe() this.callbacksAtStop = new Subscription() + this.callbacksAtStop.add( timer(0, BLOCK_POLLING_TIME).pipe(switchMap(this.api.fetchStatistics)).subscribe(this.latestStatistics$), ) @@ -52,6 +64,28 @@ class ExplorerService { ) .subscribe(this.latestBlockNumber$), ) + + this.callbacksAtStop.add( + timer(0, BLOCKCHAIN_ALERT_POLLING_TIME) + .pipe( + switchMap(this.api.fetchBlockchainInfo), + map(wrapper => (wrapper?.attributes.blockchainInfo.alerts ?? []).map(alert => alert.message)), + ) + .subscribe(this.blockchainAlerts$), + ) + + this.callbacksAtStop.add( + timer(0, FLUSH_CHART_CACHE_POLLING_TIME) + .pipe( + switchMap(this.api.fetchFlushChartCache), + map(({ flushCacheInfo }) => { + if (flushCacheInfo.length === 0) return + + this.cacheService.clear() + }), + ) + .subscribe(), + ) } stop() { @@ -59,7 +93,7 @@ class ExplorerService { } } -export const explorerService = new ExplorerService() +export const explorerService = new ExplorerService(cacheService) export * from './hooks' export * from './types' diff --git a/src/services/ExplorerService/requester.ts b/src/services/ExplorerService/requester.ts index 8a06de0b2..175a1e9b5 100644 --- a/src/services/ExplorerService/requester.ts +++ b/src/services/ExplorerService/requester.ts @@ -1,6 +1,8 @@ import axios, { AxiosError } from 'axios' +import { BehaviorSubject } from 'rxjs' import CONFIG from '../../config' -import { setNetworkErrMsgs } from '../../components/Sheet' + +export const networkErrMsgs$ = new BehaviorSubject([]) export const requesterV1 = axios.create({ baseURL: `${CONFIG.API_URL}/api/v1/`, @@ -28,10 +30,10 @@ const updateNetworkError = (errMessage = 'toast.invalid_network') => { clearTimeout(timeout) } timeout = setTimeout(() => { - setNetworkErrMsgs([]) + networkErrMsgs$.next([]) timeout = null }, 2000) - setNetworkErrMsgs([errMessage]) + networkErrMsgs$.next([errMessage]) } requesterV1.interceptors.request.use( diff --git a/src/services/PersistenceService/index.ts b/src/services/PersistenceService/index.ts new file mode 100644 index 000000000..2670ac459 --- /dev/null +++ b/src/services/PersistenceService/index.ts @@ -0,0 +1,66 @@ +import { BooleanT } from '../../utils/array' + +export const NAMESPACE_PS = 'ps' + +export const KEY_DATA_VERSION = `${NAMESPACE_PS}_dataVersion` + +export class PersistenceService { + oldDataVersion = this.get(KEY_DATA_VERSION) + + currentDataVersion = '1' + + dataVersionChanged = this.oldDataVersion !== this.currentDataVersion + + constructor() { + this.handleDataMigration() + this.set(KEY_DATA_VERSION, this.currentDataVersion) + } + + handleDataMigration() { + if (!this.dataVersionChanged) return + + switch (this.oldDataVersion) { + case null: + case undefined: + localStorage.clear() + break + + default: + break + } + } + + get(key: string): T | undefined + get(key: string, defaultValue: T): T + get(key: string, defaultValue?: T): T | undefined { + const jsonStr = localStorage.getItem(key) + if (!jsonStr) return defaultValue + try { + return JSON.parse(jsonStr) as T + } catch (err) { + // Here, it can only be a serialization error, which should be treated as data corruption that cannot be auto fixed. + // Swallowing this error should have no impact. + return defaultValue + } + } + + set(key: string, value: T): T { + localStorage.setItem(key, JSON.stringify(value)) + return value + } + + remove(key: string): void { + localStorage.removeItem(key) + } + + getAllKeys() { + return new Array(localStorage.length) + .fill(null) + .map((_, idx) => localStorage.key(idx)) + .filter(BooleanT()) + } + + // TODO: Consider providing a change event or changeEvent$. +} + +export const persistenceService = new PersistenceService() diff --git a/src/utils/cache.ts b/src/utils/cache.ts deleted file mode 100644 index ec48d6c12..000000000 --- a/src/utils/cache.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { getCSTTime } from './date' - -export const storeCachedData = (key: string, value: T) => { - try { - localStorage.setItem(key, JSON.stringify(value)) - } catch (e) { - localStorage.removeItem(key) - } -} - -export const fetchCachedData = (key: string): T | null => { - const data: string | null = localStorage.getItem(key) - if (data) { - try { - const object = JSON.parse(data) as T - if (object) { - return object - } - } catch (error) { - console.error(error) - } - } - return null -} - -export const removeCachedData = (key: string) => { - localStorage.removeItem(key) -} - -export const storeDateChartCache = (key: string, value: T) => { - // cacheKey format: key + & + CST timestamp - let cacheKey = fetchCachedData(key) - // Detect stored data and if null, remove it - if (cacheKey && fetchCachedData(cacheKey)) { - localStorage.removeItem(cacheKey) - } - cacheKey = `${key}&${getCSTTime()}` - storeCachedData(key, cacheKey) - storeCachedData(cacheKey, value) -} - -export const fetchDateChartCache = (key: string): T | null => { - // cacheKey format: key + & + CST timestamp - const cacheKey = fetchCachedData(key) - if (!cacheKey) return null - const storeTime = Number(cacheKey.substring(cacheKey.indexOf('&') + 1)) - const now = new Date(getCSTTime()) // current CST time - // Chart data will be updated at 0:10(CST) every day - const dataUpdateTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 10, 0).getTime() - // If last storage time is bigger than data update time, return cache data. Otherwise return null - return storeTime > dataUpdateTime ? fetchCachedData(cacheKey) : null -} - -export const storeEpochChartCache = (key: string, value: T) => { - storeDateChartCache(key, value) -} - -const ThreeHours = 3 * 60 * 60 * 1000 -export const fetchEpochChartCache = (key: string): T | null => { - // cacheKey format: key + & + CST timestamp - const cacheKey = fetchCachedData(key) - if (!cacheKey) return null - const storeTime = Number(cacheKey.substring(cacheKey.indexOf('&') + 1)) - // If last storage time is bigger than data update time, return cache data. Otherwise return null - return getCSTTime() - storeTime < ThreeHours ? fetchCachedData(cacheKey) : null -} - -export default { - storeCachedData, - fetchCachedData, - storeDateChartCache, - fetchDateChartCache, - storeEpochChartCache, - fetchEpochChartCache, -} diff --git a/src/utils/date.ts b/src/utils/date.ts index e5dcb7cd3..472e67fde 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -1,6 +1,7 @@ import dayjs from 'dayjs' import relativeTime from 'dayjs/plugin/relativeTime' import updateLocale from 'dayjs/plugin/updateLocale' +import utc from 'dayjs/plugin/utc' import 'dayjs/locale/zh-cn' import 'dayjs/locale/en' import BigNumber from 'bignumber.js' @@ -10,6 +11,7 @@ import { useTranslation } from 'react-i18next' dayjs.extend(relativeTime) dayjs.extend(updateLocale) +dayjs.extend(utc) dayjs.extend(weekday) dayjs.extend(localeData) @@ -98,10 +100,3 @@ export const parseHourFromMillisecond = (millisecond: string) => { const minutes = new BigNumber(millisecond).div(1000 * 60, 10).toNumber() return parseHourFromMinute(minutes) } - -export const getCSTTime = () => { - const date = new Date() - const offsetGMT = date.getTimezoneOffset() // minutes - const now = date.getTime() - return now + (offsetGMT + 8 * 60) * 60 * 1000 -} diff --git a/src/utils/hook.ts b/src/utils/hook.ts index 11dd9783a..7f19c7b89 100644 --- a/src/utils/hook.ts +++ b/src/utils/hook.ts @@ -11,22 +11,22 @@ import { useHistory, useLocation } from 'react-router-dom' import { useQuery } from '@tanstack/react-query' import { useResizeDetector } from 'react-resize-detector' import { interval, share } from 'rxjs' -import { AppCachedKeys } from '../constants/cache' +import dayjs from 'dayjs' import { deprecatedAddrToNewAddr } from './util' import { startEndEllipsis } from './string' -import { ListPageParams, PageParams, THEORETICAL_EPOCH_TIME, EPOCHS_PER_HALVING } from '../constants/common' import { - fetchCachedData, - fetchDateChartCache, - fetchEpochChartCache, - storeCachedData, - storeDateChartCache, - storeEpochChartCache, -} from './cache' + ListPageParams, + PageParams, + THEORETICAL_EPOCH_TIME, + EPOCHS_PER_HALVING, + ONE_YEAR_MILLISECOND, + ONE_HOUR_MILLISECOND, +} from '../constants/common' import { omit } from './object' // TODO: This file depends on higher-level abstractions, so it should not be in the utils folder. It should be moved to `src/hooks/index.ts`. import { useParseDate } from './date' import { Response, useStatistics } from '../services/ExplorerService' +import { cacheService } from '../services/CacheService' /** * Returns the value of the argument from the previous render @@ -424,18 +424,6 @@ export function useAdaptPCEllipsis(factor = 40) { return adaptPCEllipsis } -export const useAddrFormatToggle = () => { - const [isNew, setIsNew] = useState(localStorage.getItem(AppCachedKeys.NewAddrFormat) !== 'false') - - return { - isNew, - setIsNew: (is: boolean) => { - localStorage.setItem(AppCachedKeys.NewAddrFormat, `${is}`) - setIsNew(is) - }, - } -} - export const useNewAddr = (addr: string) => useMemo(() => { if (addr.startsWith('0x')) { @@ -528,10 +516,7 @@ export function useChartQueryWithCache( ) { return useQuery([fetchData, cacheKey, cacheMode], async () => { if (cacheKey) { - const fetchCache = - // eslint-disable-next-line no-nested-ternary - cacheMode === 'forever' ? fetchCachedData : cacheMode === 'date' ? fetchDateChartCache : fetchEpochChartCache - const dataList = fetchCache(cacheKey) + const dataList = cacheService.get(cacheKey) if (dataList) return dataList } @@ -540,10 +525,25 @@ export function useChartQueryWithCache( dataList = dataList.data.map(wrapper => wrapper.attributes) } if (cacheKey && dataList.length > 0) { - const storeCache = - // eslint-disable-next-line no-nested-ternary - cacheMode === 'forever' ? storeCachedData : cacheMode === 'date' ? storeDateChartCache : storeEpochChartCache - storeCache(cacheKey, dataList) + let expireAt: Date | number + switch (cacheMode) { + case 'epoch': + expireAt = Date.now() + ONE_HOUR_MILLISECOND * 3 + break + case 'date': { + // Chart data will be updated at 08:10(CST) every day + const now = dayjs().utc() + const todayUpdateTime = now.hour(8).minute(11).second(0).millisecond(0) + const nextUpdateTime = now.isBefore(todayUpdateTime) ? todayUpdateTime : todayUpdateTime.add(1, 'day') + expireAt = nextUpdateTime.toDate() + break + } + case 'forever': + default: + expireAt = Date.now() + ONE_YEAR_MILLISECOND * 100 + break + } + cacheService.set(cacheKey, dataList, { expireAt }) } return dataList }) @@ -611,9 +611,9 @@ export const useSingleHalving = (_halvingCount = 1) => { const halvingCount = Math.max(Math.floor(_halvingCount) || 1, 1) // halvingCount should be a positive integer greater than 1. const statistics = useStatistics() const celebrationSkipKey = `having-celebration-${halvingCount}` - const celebrationSkipped = fetchCachedData(celebrationSkipKey) !== null + const celebrationSkipped = cacheService.get(celebrationSkipKey) ?? false function skipCelebration() { - storeCachedData(celebrationSkipKey, true) + cacheService.set(celebrationSkipKey, true) } const currentEpoch = Number(statistics.epochInfo.epochNumber) @@ -654,6 +654,5 @@ export default { useInterval, useTimeout, useTimeoutWithUnmount, - useAddrFormatToggle, useNewAddr, } diff --git a/src/utils/i18n.ts b/src/utils/i18n.ts index 0ec0b9f7f..a3cade6dd 100644 --- a/src/utils/i18n.ts +++ b/src/utils/i18n.ts @@ -2,30 +2,34 @@ import i18n from 'i18next' import { initReactI18next, useTranslation } from 'react-i18next' import en from '../locales/en.json' import zh from '../locales/zh.json' -import { storeCachedData, fetchCachedData } from './cache' -import { AppCachedKeys } from '../constants/cache' +import { appSettings } from '../services/AppSettings' +import { includes } from './array' -export type LanuageType = 'en' | 'zh' +export const SupportedLngs = ['en', 'zh'] as const +export type SupportedLng = (typeof SupportedLngs)[number] +export const isSupportedLng = (value: unknown): value is SupportedLng => includes(SupportedLngs, value) -const getDefaultLanguage = () => fetchCachedData(AppCachedKeys.AppLanguage) ?? 'en' -const setDefaultLanguage = (lng: LanuageType) => storeCachedData(AppCachedKeys.AppLanguage, lng) +const getDefaultLanguage = () => appSettings.defaultLanguage$.value +const setDefaultLanguage = appSettings.defaultLanguage$.next.bind(appSettings.defaultLanguage$) i18n.use(initReactI18next).init({ resources: { en, zh, }, + supportedLngs: SupportedLngs, + // Here, `fallbackLng` is used instead of `lng`, perhaps to continue using the results of automatic region checking? fallbackLng: getDefaultLanguage(), interpolation: { escapeValue: false, }, }) -i18n.on('languageChanged', (lng: LanuageType) => { - setDefaultLanguage(lng) +i18n.on('languageChanged', lng => { + setDefaultLanguage(isSupportedLng(lng) ? lng : 'en') }) -export const useCurrentLanguage = (): LanuageType => { +export const useCurrentLanguage = (): SupportedLng => { const { i18n } = useTranslation() const currentLanguage = i18n.language if (currentLanguage !== 'en' && currentLanguage !== 'zh') { diff --git a/src/utils/typescript.ts b/src/utils/typescript.ts new file mode 100644 index 000000000..15de5a725 --- /dev/null +++ b/src/utils/typescript.ts @@ -0,0 +1,11 @@ +export type MutexAttr = + | ({ + [K1 in keyof T1]: T1[K1] + } & { + [K2 in keyof T2]?: never + }) + | ({ + [K1 in keyof T1]?: never + } & { + [K2 in keyof T2]: T2[K2] + }) From 366cf4158749f864bfc77907dfae5499b449d655 Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Tue, 7 Nov 2023 15:42:33 +0900 Subject: [PATCH 2/3] fix: fix frozen avg-block-time chart (#138) --- .../StatisticsChart/block/AverageBlockTime.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pages/StatisticsChart/block/AverageBlockTime.tsx b/src/pages/StatisticsChart/block/AverageBlockTime.tsx index 3d426f81e..e1f926a2a 100644 --- a/src/pages/StatisticsChart/block/AverageBlockTime.tsx +++ b/src/pages/StatisticsChart/block/AverageBlockTime.tsx @@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next' import { parseDateNoTime, parseSimpleDate, parseSimpleDateNoSecond } from '../../../utils/date' import { tooltipColor, tooltipWidth, SeriesItem, SmartChartPage } from '../common' import { localeNumberString } from '../../../utils/number' -import { DATA_ZOOM_CONFIG, assertIsArray, assertSerialsDataIsString, assertSerialsItem } from '../../../utils/chart' +import { DATA_ZOOM_CONFIG, assertIsArray, assertSerialsItem } from '../../../utils/chart' import { ChartItem, explorerService } from '../../../services/ExplorerService' import { useCurrentLanguage } from '../../../utils/i18n' import { ChartColorConfig } from '../../../constants/common' @@ -42,13 +42,13 @@ const useOption = ( const widthSpan = (value: string) => tooltipWidth(value, currentLanguage === 'en' ? 180 : 100) - const parseTooltip = ({ seriesName, data, color }: SeriesItem & { data: string }): string => { - if (seriesName === t('statistic.daily_moving_average')) { + const parseTooltip = ({ seriesName, data, color }: SeriesItem & { data?: string[] }): string => { + if (seriesName === t('statistic.daily_moving_average') && data?.[1]) { return `
${tooltipColor(color)}${widthSpan(t('statistic.daily_moving_average'))} ${localeNumberString( data[1], )}
` } - if (seriesName === t('statistic.weekly_moving_average')) { + if (seriesName === t('statistic.weekly_moving_average') && data?.[2]) { return `
${tooltipColor(color)}${widthSpan(t('statistic.weekly_moving_average'))} ${localeNumberString( data[2], )}
` @@ -69,8 +69,7 @@ const useOption = ( )}
` dataList.forEach(data => { assertSerialsItem(data) - assertSerialsDataIsString(data) - result += parseTooltip(data) + result += parseTooltip({ ...data }) }) return result }, @@ -89,7 +88,8 @@ const useOption = ( } : undefined, grid: isThumbnail ? gridThumbnail : grid, - dataZoom: isThumbnail ? [] : DATA_ZOOM_CONFIG, + /* Selection starts from 1% because the average block time is extremely high on launch */ + dataZoom: isThumbnail ? [] : DATA_ZOOM_CONFIG.map(zoom => ({ ...zoom, start: 1 })), xAxis: [ { name: isMobile || isThumbnail ? '' : t('statistic.date'), From a2a22de9cd03966727c2ec279a8b9045cb45a8e5 Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Tue, 7 Nov 2023 15:55:32 +0900 Subject: [PATCH 3/3] feat: set start point of selection of avg-block-time 1% (#137) --- src/pages/StatisticsChart/block/AverageBlockTime.tsx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/pages/StatisticsChart/block/AverageBlockTime.tsx b/src/pages/StatisticsChart/block/AverageBlockTime.tsx index e1f926a2a..1b72c92e6 100644 --- a/src/pages/StatisticsChart/block/AverageBlockTime.tsx +++ b/src/pages/StatisticsChart/block/AverageBlockTime.tsx @@ -32,14 +32,6 @@ const useOption = ( containLabel: true, } - const maxAndMinAxis = (statisticAverageBlockTimes: ChartItem.AverageBlockTime[]) => { - const array = statisticAverageBlockTimes.flatMap(data => parseFloat(data.avgBlockTimeDaily)) - return { - max: Math.ceil(Math.max(...array) / 1000), - min: Math.floor(Math.min(...array) / 1000), - } - } - const widthSpan = (value: string) => tooltipWidth(value, currentLanguage === 'en' ? 180 : 100) const parseTooltip = ({ seriesName, data, color }: SeriesItem & { data?: string[] }): string => { @@ -114,8 +106,6 @@ const useOption = ( nameTextStyle: { align: 'left', }, - max: () => maxAndMinAxis(statisticAverageBlockTimes).max, - min: () => maxAndMinAxis(statisticAverageBlockTimes).min, axisLine: { lineStyle: { color: chartColor.colors[0], @@ -133,8 +123,6 @@ const useOption = ( nameTextStyle: { align: 'right', }, - max: () => maxAndMinAxis(statisticAverageBlockTimes).max, - min: () => maxAndMinAxis(statisticAverageBlockTimes).min, axisLine: { lineStyle: { color: chartColor.colors[1],