diff --git a/.env b/.env index 1c5ff054d..7ce24f8c8 100644 --- a/.env +++ b/.env @@ -9,7 +9,6 @@ VITE_TOKEN=SQT VITE_STABLE_TOKEN=USDC.e VITE_STABLE_TOKEN_ADDRESS=0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 VITE_FLEXPLAN_ENABLED=true -VITE_STUDIO_ENABLED=false VITE_NETWORK=mainnet VITE_GQL_PROXY=https://gql-proxy.subquery.network VITE_AUTH_URL=https://kepler-auth.subquery.network diff --git a/.env.staging b/.env.staging index d36f722cb..df221405c 100644 --- a/.env.staging +++ b/.env.staging @@ -9,7 +9,6 @@ VITE_TOKEN=SQT VITE_STABLE_TOKEN=USDC.e VITE_STABLE_TOKEN_ADDRESS=0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 VITE_FLEXPLAN_ENABLED=true -VITE_STUDIO_ENABLED=false VITE_NETWORK=mainnet VITE_GQL_PROXY=https://gql-proxy.subquery.network VITE_AUTH_URL=https://kepler-auth.subquery.network diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index e0d174127..5cdf84d93 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -4,7 +4,6 @@ import * as React from 'react'; import { useNavigate } from 'react-router-dom'; import { AccountActions } from '@components/AccountActions'; -import { useStudioEnabled } from '@hooks'; import { ConnectButton } from '@rainbow-me/rainbowkit'; import { Button, Header as SubqlHeader } from '@subql/components'; import { entryLinks, externalAppLinks } from '@utils/links'; @@ -38,21 +37,17 @@ export interface AppNavigation { export const Header: React.FC = () => { const { address: account } = useAccount(); const navigate = useNavigate(); - const studioEnabled = useStudioEnabled(); const calEntryLinks = React.useMemo(() => { - if (!studioEnabled) { - return entryLinks.map((entry) => { - if (entry.key === 'explorer') { - return { - ...entry, - dropdown: undefined, - }; - } - return entry; - }); - } - return entryLinks; - }, [studioEnabled]); + return entryLinks.map((entry) => { + if (entry.key === 'explorer') { + return { + ...entry, + dropdown: undefined, + }; + } + return entry; + }); + }, []); return (
diff --git a/src/components/IndexerDetails/Row.tsx b/src/components/IndexerDetails/Row.tsx index f4566f0b7..e3504d9b5 100644 --- a/src/components/IndexerDetails/Row.tsx +++ b/src/components/IndexerDetails/Row.tsx @@ -125,10 +125,12 @@ const ConnectedRow: React.FC<{ setProjectMaxTargetHeightInfo(deploymentId, maxTargetHeight); } + console.warn(meta); + return { startBlock: meta?.startHeight ?? 0, targetBlock: maxTargetHeight, - currentBlock: meta?.lastProcessedHeight ?? 0, + currentBlock: meta?.lastHeight ?? 0, }; }, [indexerMetadata.url, indexer]); diff --git a/src/hooks/useSortedIndexer.tsx b/src/hooks/useSortedIndexer.tsx index a256aa384..cc65b92fe 100644 --- a/src/hooks/useSortedIndexer.tsx +++ b/src/hooks/useSortedIndexer.tsx @@ -61,16 +61,15 @@ export interface UseSortedIndexerReturn { } export function useSortedIndexer(account: string): AsyncData & { refresh?: () => void } { - const { currentEra, refetch } = useEra(); + const { currentEra } = useEra(); const indexerQueryParams = { address: account ?? '' }; - const indexerData = useGetIndexerQuery({ variables: indexerQueryParams, pollInterval: 10000 }); + const indexerData = useGetIndexerQuery({ variables: indexerQueryParams, fetchPolicy: 'network-only' }); const delegationQueryParams = { id: `${account ?? ''}:${account}` }; - const indexerDelegation = useGetDelegationQuery({ variables: delegationQueryParams }); + const indexerDelegation = useGetDelegationQuery({ variables: delegationQueryParams, fetchPolicy: 'network-only' }); const { loading, error, data } = mergeAsync(currentEra, indexerData, indexerDelegation); const refresh = async () => { - refetch(); indexerData.refetch(); indexerDelegation.refetch(); }; diff --git a/src/pages/account/Rewards/Rewards.tsx b/src/pages/account/Rewards/Rewards.tsx index 06d9cc855..e03b2792e 100644 --- a/src/pages/account/Rewards/Rewards.tsx +++ b/src/pages/account/Rewards/Rewards.tsx @@ -11,6 +11,7 @@ import { TableTitle } from '@subql/components'; import { GetEraRewardsByIndexerAndPageQuery } from '@subql/network-query'; import { renderAsync, useGetEraRewardsByIndexerAndPageLazyQuery, useGetRewardsQuery } from '@subql/react-hooks'; import { ExcludeNull, formatEther, notEmpty } from '@utils'; +import { retry } from '@utils/retry'; import { useMount, useUpdate } from 'ahooks'; import { Table, TableProps, Tag, Tooltip } from 'antd'; import dayjs from 'dayjs'; @@ -26,6 +27,8 @@ export const Rewards: React.FC = () => { const update = useUpdate(); const filterParams = { address: account || '' }; const rewards = useGetRewardsQuery({ variables: filterParams, fetchPolicy: 'network-only' }); + + const [loading, setLoading] = React.useState(false); const queryParams = React.useRef({ offset: 0, pageSize: 10, @@ -117,62 +120,80 @@ export const Rewards: React.FC = () => { fetchIndexerEraRewards(); }, [account]); - useMount(() => { - fetchIndexerEraRewards(); + useMount(async () => { + try { + setLoading(true); + fetchIndexerEraRewards(); + } finally { + setLoading(false); + } }); return (
- {renderAsync(indexerEraRewards, { - error: (error) => {`Failed to get pending rewards: ${error.message}`}, - loading: () => , - data: (data) => { - const filterEmptyData = data.eraRewards?.nodes.filter(notEmpty); - return ( - <> -
- - {t('rewards.info')} - - {totalUnclaimedRewards > 0 && unclaimedRewards?.indexers && ( - - )} -
-
- - {t('rewards.totalUnclaimReward', { count: totalUnclaimedRewards })} - -
+ {renderAsync( + { + ...indexerEraRewards, + loading, + }, + { + error: (error) => {`Failed to get pending rewards: ${error.message}`}, + loading: () => , + data: (data) => { + const filterEmptyData = data.eraRewards?.nodes.filter(notEmpty); + return ( + <> +
+ + {t('rewards.info')} + + {totalUnclaimedRewards > 0 && unclaimedRewards?.indexers && ( + { + retry(() => { + fetchIndexerEraRewards(); + rewards.refetch(); + }); + }} + /> + )} +
+
+ + {t('rewards.totalUnclaimReward', { count: totalUnclaimedRewards })} + +
- - - ); +
+ + ); + }, }, - })} + )} ); diff --git a/src/pages/account/Staking/index.tsx b/src/pages/account/Staking/index.tsx index 378bf0aa7..ce1083997 100644 --- a/src/pages/account/Staking/index.tsx +++ b/src/pages/account/Staking/index.tsx @@ -18,7 +18,8 @@ import Breakdown from './Breakdown'; import styles from './index.module.less'; const Staking: FC = () => { - const { address: account } = useAccount(); + // const { address: account } = useAccount(); + const account = '0x21A787fddeF5b69A8a1065a05E364f7382c8cdAc'; const navigate = useNavigate(); const indexerDelegators = useGetIndexerDelegatorsQuery({ variables: { id: account ?? '', offset: 0 } }); @@ -28,7 +29,7 @@ const Staking: FC = () => { account: account || '', }, }); - + console.warn(delegateToOthersByEra); const totalStaked = useMemo(() => { return sortedIndexer.data?.totalStake; }, [sortedIndexer]); diff --git a/src/pages/account/Withdrawn/Locked/DoWithdraw/DoWithdraw.tsx b/src/pages/account/Withdrawn/Locked/DoWithdraw/DoWithdraw.tsx index 967b05843..3e0b1e306 100644 --- a/src/pages/account/Withdrawn/Locked/DoWithdraw/DoWithdraw.tsx +++ b/src/pages/account/Withdrawn/Locked/DoWithdraw/DoWithdraw.tsx @@ -17,9 +17,10 @@ import styles from './DoWithdraw.module.css'; interface DoWithdrawProps { unlockedAmount: string; disabled: boolean; + onSuccess: () => void; } -export const DoWithdraw: React.FC = ({ unlockedAmount, disabled }) => { +export const DoWithdraw: React.FC = ({ unlockedAmount, disabled, onSuccess }) => { const { t } = useTranslation(); const { contracts } = useWeb3Store(); @@ -44,6 +45,7 @@ export const DoWithdraw: React.FC = ({ unlockedAmount, disabled variant={disabled ? 'disabledButton' : 'button'} onClick={handleClick} buttonClassName={styles.withdrawButton} + onSuccess={onSuccess} renderContent={(onSubmit, _, isLoading, error) => { return ( <> diff --git a/src/pages/account/Withdrawn/Locked/Home/Locked.module.less b/src/pages/account/Withdrawn/Locked/Home/Locked.module.less index 9efcc547d..860c3ccf3 100644 --- a/src/pages/account/Withdrawn/Locked/Home/Locked.module.less +++ b/src/pages/account/Withdrawn/Locked/Home/Locked.module.less @@ -25,7 +25,6 @@ // TODO: replace it when components finishi .cancelModal { :global .ant-modal-content { - padding: 32px; .ant-modal-close { display: none; } diff --git a/src/pages/account/Withdrawn/Locked/Home/Locked.tsx b/src/pages/account/Withdrawn/Locked/Home/Locked.tsx index eef344b7c..a928ded9b 100644 --- a/src/pages/account/Withdrawn/Locked/Home/Locked.tsx +++ b/src/pages/account/Withdrawn/Locked/Home/Locked.tsx @@ -5,23 +5,25 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; import { BsExclamationCircle } from 'react-icons/bs'; import InfoCircleOutlined from '@ant-design/icons/InfoCircleOutlined'; -import { EmptyList } from '@components'; +import { claimIndexerRewardsModalText, EmptyList, ModalClaimIndexerRewards } from '@components'; import { TokenAmount } from '@components/TokenAmount'; import TransactionModal from '@components/TransactionModal'; import { useWeb3 } from '@containers'; import { defaultLockPeriod, useLockPeriod } from '@hooks'; +import { useRewardCollectStatus } from '@hooks/useRewardCollectStatus'; import { Spinner, Typography } from '@subql/components'; import { TableText, TableTitle } from '@subql/components'; import { WithdrawalFieldsFragment as Withdrawls, WithdrawalType } from '@subql/network-query'; import { useGetWithdrawlsLazyQuery } from '@subql/react-hooks'; import { WithdrawalStatus } from '@subql/react-hooks/dist/graphql'; import { formatEther, LOCK_STATUS, mapAsync, mergeAsync, notEmpty, renderAsyncArray } from '@utils'; +import { retry } from '@utils/retry'; import { Button, Table, TableProps, Tag } from 'antd'; import assert from 'assert'; +import dayjs from 'dayjs'; import { BigNumber } from 'ethers'; import { t } from 'i18next'; import { capitalize } from 'lodash-es'; -import moment from 'moment'; import { useWeb3Store } from 'src/stores'; @@ -61,19 +63,30 @@ const CancelUnbonding: React.FC<{ id: string; type: WithdrawalType; onSuccess?: onSuccess, }) => { const { contracts } = useWeb3Store(); + const { account } = useWeb3(); + const rewardClaimStatus = useRewardCollectStatus(account || ''); + const cancelUnbonding = () => { assert(contracts, 'Contracts not available'); return contracts.stakingManager.cancelUnbonding(id); }; + const needClaimedStatus = React.useMemo(() => { + return !rewardClaimStatus.data?.hasClaimedRewards; + }, [rewardClaimStatus.data?.hasClaimedRewards]); + return (
{ + if (needClaimedStatus) { + return rewardClaimStatus.refetch()} indexer={account ?? ''} />; + } + return (
@@ -141,7 +158,8 @@ export const Locked: React.FC = () => { { title: , width: '10%', - render: (t, r, index) => , + dataIndex: 'index', + render: (t) => , }, { title: , @@ -153,7 +171,7 @@ export const Locked: React.FC = () => { title: , dataIndex: 'endAt', width: '25%', - render: (value: string) => , + render: (value: string) => , }, { title: , @@ -175,7 +193,15 @@ export const Locked: React.FC = () => { title: , dataIndex: 'index', width: '25%', - render: (id, record) => , + render: (id, record) => ( + { + retry(getWithdrawals); + }} + > + ), }, ]; @@ -189,9 +215,9 @@ export const Locked: React.FC = () => { mapAsync( ([withdrawlsResult, lockPeriod]) => withdrawlsResult?.withdrawls?.nodes.filter(notEmpty).map((withdrawal, idx) => { - const utcStartAt = moment.utc(withdrawal?.startTime); - const utcEndAt = moment.utc(utcStartAt).add(lockPeriod || defaultLockPeriod, 'second'); - const lockStatus = moment.utc() > utcEndAt ? LOCK_STATUS.UNLOCK : LOCK_STATUS.LOCK; + const utcStartAt = dayjs.utc(withdrawal?.startTime); + const utcEndAt = dayjs.utc(utcStartAt).add(lockPeriod || defaultLockPeriod, 'second'); + const lockStatus = dayjs.utc() > utcEndAt ? LOCK_STATUS.UNLOCK : LOCK_STATUS.LOCK; return { ...withdrawal, endAt: utcEndAt.local().format(), lockStatus, idx }; }), mergeAsync(withdrawals, lockPeriod), @@ -201,7 +227,7 @@ export const Locked: React.FC = () => { loading: () => , empty: () => , data: (data) => { - const sortedData = data.sort((a, b) => moment(b.endAt).unix() - moment(a.endAt).unix()); + const sortedData = data.sort((a, b) => dayjs(b.endAt).unix() - dayjs(a.endAt).unix()); const unlockedRewards = data.filter((withdrawal) => withdrawal.lockStatus === LOCK_STATUS.UNLOCK); const hasUnlockedRewards = unlockedRewards?.length > 0; const withdrawalsAmountBigNumber = unlockedRewards.reduce((sum, withdrawal) => { @@ -219,7 +245,13 @@ export const Locked: React.FC = () => { {t('withdrawals.info')} - + { + retry(getWithdrawals); + }} + unlockedAmount={sortedWithdrawalsAmount} + disabled={!hasUnlockedRewards} + />
{headerTitle} diff --git a/src/pages/consumer/MyOffers/CancelOffer.tsx b/src/pages/consumer/MyOffers/CancelOffer.tsx index d157e540c..a9975a7cd 100644 --- a/src/pages/consumer/MyOffers/CancelOffer.tsx +++ b/src/pages/consumer/MyOffers/CancelOffer.tsx @@ -115,7 +115,7 @@ export const CancelOffer: React.FC = ({ offerId, active, onSuccess }) => onClick={handleClick} onSuccess={() => { if (onSuccess) { - setTimeout(() => onSuccess(), 1000); + onSuccess(); } }} renderContent={(onSubmit, _, isLoading, error) => { diff --git a/src/pages/consumer/MyOffers/CreateOffer/Summary/Summary.tsx b/src/pages/consumer/MyOffers/CreateOffer/Summary/Summary.tsx index c19b95add..5a76460ce 100644 --- a/src/pages/consumer/MyOffers/CreateOffer/Summary/Summary.tsx +++ b/src/pages/consumer/MyOffers/CreateOffer/Summary/Summary.tsx @@ -7,6 +7,7 @@ import { useNavigate } from 'react-router'; import { NotificationType, openNotification } from '@components/Notification'; import { assert } from '@polkadot/util'; import { EVENT_TYPE, EventBus } from '@utils/eventBus'; +import { retry } from '@utils/retry'; import { Typography } from 'antd'; import dayjs from 'dayjs'; import { BigNumber } from 'ethers'; @@ -84,10 +85,9 @@ export const Summary: React.FC = () => { title: 'Offer created!', description: t('status.changeValidIn15s'), }); - - setTimeout(() => { + retry(() => { EventBus.emit(EVENT_TYPE.CREATED_CONSUMER_OFFER, 'success'); - }, 1000); + }); }); } catch (error) { openNotification({ diff --git a/src/pages/consumer/MyOffers/OfferTable.tsx b/src/pages/consumer/MyOffers/OfferTable.tsx index eeb1890d4..691f206e1 100644 --- a/src/pages/consumer/MyOffers/OfferTable.tsx +++ b/src/pages/consumer/MyOffers/OfferTable.tsx @@ -16,6 +16,7 @@ import { useGetSpecificOpenOffersLazyQuery, } from '@subql/react-hooks'; import { EVENT_TYPE, EventBus } from '@utils/eventBus'; +import { retry } from '@utils/retry'; import { TableProps, Typography } from 'antd'; import clsx from 'clsx'; import { BigNumber } from 'ethers'; @@ -54,7 +55,10 @@ const AcceptButton: React.FC<{ offer: OfferFieldsFragment }> = ({ offer }) => { }, }); - const acceptedOffersResult = useGetAcceptedOffersQuery({ variables: { address: account ?? '', offerId: offer.id } }); + const acceptedOffersResult = useGetAcceptedOffersQuery({ + variables: { address: account ?? '', offerId: offer.id }, + fetchPolicy: 'network-only', + }); return ( <> @@ -82,7 +86,9 @@ const AcceptButton: React.FC<{ offer: OfferFieldsFragment }> = ({ offer }) => { 0} - onAcceptOffer={acceptedOffersResult.refetch} + onAcceptOffer={() => { + retry(acceptedOffersResult.refetch); + }} offer={offer} requiredBlockHeight={convertBigNumberToNumber(offer.minimumAcceptHeight)} /> @@ -395,7 +401,9 @@ export const OfferTable: React.FC = ({ queryFn, queryParams, columns: getColumns( pathname as typeof CONSUMER_OPEN_OFFERS_NAV | typeof INDEXER_OFFER_MARKETPLACE_NAV, account, - refreshAfterCancel, + () => { + retry(refreshAfterCancel); + }, ), dataSource: offerList, scroll: { x: 2000 }, diff --git a/src/pages/consumer/OfferMarketplace/AcceptOffer.tsx b/src/pages/consumer/OfferMarketplace/AcceptOffer.tsx index fa53c11c6..ed408be77 100644 --- a/src/pages/consumer/OfferMarketplace/AcceptOffer.tsx +++ b/src/pages/consumer/OfferMarketplace/AcceptOffer.tsx @@ -5,9 +5,9 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; import { StepButtons } from '@components/StepButton'; import { useIndexerMetadata, useProject } from '@hooks'; -import { Spinner } from '@subql/components'; +import { openNotification, Spinner } from '@subql/components'; import { IndexerDeploymentFieldsFragment, OfferFieldsFragment } from '@subql/network-query'; -import { useGetIndexerQuery } from '@subql/react-hooks'; +import { useAsyncMemo, useGetIndexerQuery } from '@subql/react-hooks'; import { Typography } from 'antd'; import assert from 'assert'; import moment from 'moment'; @@ -23,6 +23,7 @@ import { formatEther, formatSecondsDuration, getCapitalizedStr, + getDeploymentMetadata, renderAsync, } from '../../../utils'; import styles from './AcceptOffer.module.css'; @@ -146,6 +147,21 @@ export const AcceptOffer: React.FC = ({ deployment, offer, requiredBlockH immediate: true, }); + const deploymentMeta = useAsyncMemo(async () => { + if (!deployment.deploymentId || !indexerMetadata.url || !account) return { lastHeight: 0 }; + try { + const metaData = await getDeploymentMetadata({ + deploymentId: deployment.deploymentId, + indexer: account, + proxyEndpoint: indexerMetadata.url ?? '', + }); + + return metaData; + } catch (error: unknown) { + return { lastHeight: 0, poiHash: '' }; + } + }, [deployment.deploymentId, account, indexerMetadata.url ?? '']); + const disableAcceptInfo = React.useMemo(() => { const status = disabled || !offer.planTemplate?.active; let tooltip = undefined; @@ -174,10 +190,13 @@ export const AcceptOffer: React.FC = ({ deployment, offer, requiredBlockH const handleClick = async () => { assert(contracts, 'Contracts not available'); - - // TODO: update the root when api ready - const tempMmrRoot = '0xab3921276c8067fe0c82def3e5ecfd8447f1961bc85768c2a56e6bd26d3c0c55'; - return contracts.purchaseOfferMarket.acceptPurchaseOffer(offer?.id ?? '', tempMmrRoot); + if (!deploymentMeta.data) { + openNotification({ + type: 'error', + description: 'Please confirm your metadata can be reach', + }); + } + return contracts.purchaseOfferMarket.acceptPurchaseOffer(offer?.id ?? '', deploymentMeta.data?.poiHash || ''); }; return ( @@ -217,6 +236,7 @@ export const AcceptOffer: React.FC = ({ deployment, offer, requiredBlockH onSubmit={onSubmit} isLoading={isLoading} error={error} + deploymentMeta={deploymentMeta} /> ), }); diff --git a/src/pages/consumer/OfferMarketplace/CheckList.tsx b/src/pages/consumer/OfferMarketplace/CheckList.tsx index 14a6f661b..e8ef1783f 100644 --- a/src/pages/consumer/OfferMarketplace/CheckList.tsx +++ b/src/pages/consumer/OfferMarketplace/CheckList.tsx @@ -5,6 +5,7 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; import { AiOutlineCheckCircle, AiOutlineCloseCircle } from 'react-icons/ai'; import { ServiceStatus } from '@subql/network-query'; +import { AsyncMemoReturn } from '@subql/react-hooks'; import { Button, Typography } from 'antd'; import clsx from 'clsx'; import moment from 'moment'; @@ -19,9 +20,9 @@ import { COLORS, convertStringToNumber, formatEther, - getDeploymentMetadata, isUndefined, mergeAsync, + Metadata, parseError, renderAsyncArray, TOKEN, @@ -45,12 +46,14 @@ interface IRequirementCheck { requiredValue: string | number | undefined; value: string | number | undefined; passCheck: boolean; + // eslint-disable-next-line @typescript-eslint/no-explicit-any formatFn?: (value: any) => string | number | React.ReactNode; errorMsg?: string; } interface ISortedValue { value: string | number | undefined; + // eslint-disable-next-line @typescript-eslint/no-explicit-any formatFn?: (value: any) => string | React.ReactNode; } @@ -102,24 +105,30 @@ interface ICheckList { rewardPerIndexer: string; requiredBlockHeight: number; //TODO: or should use bigInt? onSubmit: (params: unknown) => void; - error?: any; + error?: unknown; isLoading?: boolean; + deploymentMeta: AsyncMemoReturn< + | Metadata + | { + lastHeight: number; + } + | undefined + >; } export const CheckList: React.FC = ({ status, requiredBlockHeight, - deploymentId, offerId, rewardPerIndexer, planDuration, - proxyEndpoint, onSubmit, error, isLoading, + deploymentMeta, }) => { const { t } = useTranslation(); - const [checkListErr, setCheckListErr] = React.useState(parseError(error)); + const [checkListErr] = React.useState(parseError(error)); const { account: indexer } = useWeb3(); const { contractClient } = useWeb3Store(); @@ -128,17 +137,6 @@ export const CheckList: React.FC = ({ const daysOfPlan = moment.duration(planDuration, 'seconds').asDays(); const REQUIRED_DAILY_REWARD_CAP = convertStringToNumber(formatEther(rewardPerIndexer)) / Math.ceil(daysOfPlan); - const deploymentMeta = useAsyncMemo(async () => { - if (!deploymentId || !proxyEndpoint || !indexer) return { lastProcessedHeight: 0 }; - try { - const metaData = await getDeploymentMetadata({ deploymentId, indexer, proxyEndpoint }); - return metaData; - } catch (error: any) { - setCheckListErr(parseError(error)); - return { lastProcessedHeight: 0 }; - } - }, [deploymentId, indexer, proxyEndpoint]); - const dailyRewardCapacity = useAsyncMemo(async () => { if (!contractClient || !indexer) return null; return await contractClient.dailyRewardCapcity(indexer); @@ -152,7 +150,7 @@ export const CheckList: React.FC = ({ if (isUndefined(metadata) || isUndefined(cap)) return ; - const latestBlockHeight = metadata?.lastProcessedHeight; + const latestBlockHeight = metadata?.lastHeight; const dailyRewardCap = convertStringToNumber(formatEther(cap ?? 0)); const sortedRequirementCheckList = [ diff --git a/src/pages/indexer/MyPlans/Default/Default.tsx b/src/pages/indexer/MyPlans/Default/Default.tsx index 9870eecc7..c9da57f4b 100644 --- a/src/pages/indexer/MyPlans/Default/Default.tsx +++ b/src/pages/indexer/MyPlans/Default/Default.tsx @@ -8,6 +8,7 @@ import { useWeb3 } from '@containers'; import { Spinner, Typography } from '@subql/components'; import { useGetPlansQuery } from '@subql/react-hooks'; import { mapAsync, notEmpty, renderAsyncArray } from '@utils'; +import { retry } from '@utils/retry'; import List from '../List'; @@ -33,7 +34,7 @@ export const Default: React.FC = () => { data: (data) => ( parseInt(a.id || '0x00', 16) - parseInt(b.id || '0x00', 16))} - onRefresh={plans.refetch} + onRefresh={() => retry(plans.refetch)} title={t('plans.default.title')} /> ), diff --git a/src/pages/indexer/MyPlans/Specific/Specific.tsx b/src/pages/indexer/MyPlans/Specific/Specific.tsx index ad46bcd65..746467995 100644 --- a/src/pages/indexer/MyPlans/Specific/Specific.tsx +++ b/src/pages/indexer/MyPlans/Specific/Specific.tsx @@ -9,6 +9,7 @@ import { Spinner, Typography } from '@subql/components'; import { useGetSpecificPlansQuery } from '@subql/react-hooks'; import { mapAsync, notEmpty, renderAsyncArray, URLS } from '@utils'; +import { retry } from '../../../../utils/retry'; import List from '../List'; import styles from './Specific.module.css'; @@ -62,7 +63,7 @@ const Specific: React.FC = () => {
{plans ? ( - + retry(specificPlans.refetch)} /> ) : ( {t('plans.specific.nonDeployment')} )} diff --git a/src/pages/indexer/MyStaking/DoStake/DoStake.tsx b/src/pages/indexer/MyStaking/DoStake/DoStake.tsx index 0d4c74896..bbd137762 100644 --- a/src/pages/indexer/MyStaking/DoStake/DoStake.tsx +++ b/src/pages/indexer/MyStaking/DoStake/DoStake.tsx @@ -66,7 +66,7 @@ const getContentText = ( }; }; -export const DoStake: React.FC = () => { +export const DoStake: React.FC<{ onSuccess: () => void }> = ({ onSuccess }) => { const [stakeAction, setStakeAction] = React.useState(StakeAction.Stake); const { contracts } = useWeb3Store(); @@ -145,7 +145,10 @@ export const DoStake: React.FC = () => { showMaxButton: true, curAmount: formatEther(curAmount), }} - onSuccess={() => (stakeAction === StakeAction.Stake ? balance.refetch(true) : maxUnstake.refetch(true))} + onSuccess={() => { + stakeAction === StakeAction.Stake ? balance.refetch(true) : maxUnstake.refetch(true); + onSuccess(); + }} onClick={handleClick} renderContent={(onSubmit, _, loading) => { if (requireClaimIndexerRewards) { diff --git a/src/pages/indexer/MyStaking/MyStaking.tsx b/src/pages/indexer/MyStaking/MyStaking.tsx index 3f24d057b..fe25fd4fa 100644 --- a/src/pages/indexer/MyStaking/MyStaking.tsx +++ b/src/pages/indexer/MyStaking/MyStaking.tsx @@ -8,6 +8,7 @@ import { useWeb3 } from '@containers'; import { useIsIndexer, useSortedIndexer } from '@hooks'; import { Spinner, Typography } from '@subql/components'; import { mergeAsync, renderAsync, TOKEN, truncFormatEtherStr } from '@utils'; +import { retry } from '@utils/retry'; import { DoStake } from './DoStake'; import { Indexing, NotRegisteredIndexer } from './Indexing'; @@ -35,7 +36,6 @@ export const MyStaking: React.FC = () => { if (!data) return null; const [sortedIndexerData, indexer] = data; - if (indexer === undefined && !sortedIndexerData) return ; if (!indexer && !sortedIndexerData) return ; const sortedTotalStaking = truncFormatEtherStr(`${sortedIndexerData?.ownStake.current ?? 0}`); @@ -47,14 +47,22 @@ export const MyStaking: React.FC = () => {
- {sortedIndexerData && ( + {
- + { + retry(sortedIndexer.refresh); + }} + />
- + { + retry(sortedIndexer.refresh); + }} + />
- )} + }
diff --git a/src/pages/indexer/MyStaking/SetCommissionRate/SetCommissionRate.tsx b/src/pages/indexer/MyStaking/SetCommissionRate/SetCommissionRate.tsx index e541d7443..b597f8f55 100644 --- a/src/pages/indexer/MyStaking/SetCommissionRate/SetCommissionRate.tsx +++ b/src/pages/indexer/MyStaking/SetCommissionRate/SetCommissionRate.tsx @@ -30,7 +30,7 @@ const getModalText = (requireClaimIndexerRewards = false, commissionRate: string }; }; -export const SetCommissionRate: React.FC = () => { +export const SetCommissionRate: React.FC<{ onSuccess: () => void }> = ({ onSuccess }) => { const { contracts } = useWeb3Store(); const { t } = useTranslation(); const { account } = useWeb3(); @@ -75,7 +75,10 @@ export const SetCommissionRate: React.FC = () => { unit: '%', }} onClick={handleClick} - onSuccess={() => commissionRate.refetch(true)} + onSuccess={() => { + commissionRate.refetch(true); + onSuccess(); + }} renderContent={(onSubmit, _, loading) => { if (requireClaimIndexerRewards) { return rewardClaimStatus.refetch()} indexer={account ?? ''} />; diff --git a/src/pages/studio/Create/Create.tsx b/src/pages/studio/Create/Create.tsx index cba6f1e76..23d7e7a1f 100644 --- a/src/pages/studio/Create/Create.tsx +++ b/src/pages/studio/Create/Create.tsx @@ -239,7 +239,7 @@ const Create: React.FC = () => { onChange={(val) => { form.setFieldValue(field.name, val.target.value); }} - disabled={isEdit ? true : false} + disabled={true} > SubQuery RPC diff --git a/src/pages/studio/index.tsx b/src/pages/studio/index.tsx index 6c4e4b0b5..68978c909 100644 --- a/src/pages/studio/index.tsx +++ b/src/pages/studio/index.tsx @@ -2,9 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 import * as React from 'react'; -import { Route, Routes, useNavigate } from 'react-router'; +import { Route, Routes } from 'react-router'; import { WalletRoute } from '@components'; -import { useStudioEnabled } from '@hooks'; import { Footer } from '@subql/components'; import Create from './Create'; @@ -12,11 +11,6 @@ import Home from './Home'; import Project from './Project'; const Studio: React.FC = () => { - const studioEnabled = useStudioEnabled(); - const navigate = useNavigate(); - if (!studioEnabled) { - navigate('/'); - } return ( >( cachedResult.set(cacheName, result); setTimeout(() => { cachedResult.delete(cacheName); - }, 15000); + }, 3000); } return result; } catch (e) { diff --git a/src/utils/retry.ts b/src/utils/retry.ts new file mode 100644 index 000000000..60594a1ef --- /dev/null +++ b/src/utils/retry.ts @@ -0,0 +1,14 @@ +// Copyright 2020-2022 SubQuery Pte Ltd authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export const retry = (func: any, sleepTime = 3000) => { + let times = 0; + + const clear = setInterval(() => { + func(); + times += 1; + if (times === 5) { + clearInterval(clear); + } + }, sleepTime); +};