diff --git a/.changeset/clear-toes-begin.md b/.changeset/clear-toes-begin.md new file mode 100644 index 00000000..61fc66fb --- /dev/null +++ b/.changeset/clear-toes-begin.md @@ -0,0 +1,5 @@ +--- +"@stakekit/widget": patch +--- + +fix: activity item header margin diff --git a/.changeset/forty-queens-dig.md b/.changeset/forty-queens-dig.md new file mode 100644 index 00000000..2ffce888 --- /dev/null +++ b/.changeset/forty-queens-dig.md @@ -0,0 +1,5 @@ +--- +"@stakekit/widget": patch +--- + +refactor: request error retry on api client level diff --git a/packages/widget/src/common/check-gas-amount.ts b/packages/widget/src/common/check-gas-amount.ts index 90aca2b1..2b0544fe 100644 --- a/packages/widget/src/common/check-gas-amount.ts +++ b/packages/widget/src/common/check-gas-amount.ts @@ -7,7 +7,6 @@ import { } from "@stakekit/api-hooks"; import BigNumber from "bignumber.js"; import { EitherAsync, Left, List, Right } from "purify-ts"; -import { withRequestErrorRetry } from "./utils"; type CheckGasAmountIfStake = | { isStake: true; stakeToken: TokenDto; stakeAmount: BigNumber } @@ -21,9 +20,7 @@ export const checkGasAmount = ({ addressWithTokenDto: AddressWithTokenDto; gasEstimate: ActionDtoWithGasEstimate["gasEstimate"]; } & CheckGasAmountIfStake) => - withRequestErrorRetry({ - fn: () => tokenGetTokenBalances({ addresses: [addressWithTokenDto] }), - }) + EitherAsync(() => tokenGetTokenBalances({ addresses: [addressWithTokenDto] })) .mapLeft(() => new GetGasTokenError()) .chain((res) => EitherAsync.liftEither( diff --git a/packages/widget/src/common/get-gas-mode-value.ts b/packages/widget/src/common/get-gas-mode-value.ts index 488b2506..e9232ba2 100644 --- a/packages/widget/src/common/get-gas-mode-value.ts +++ b/packages/widget/src/common/get-gas-mode-value.ts @@ -3,14 +3,13 @@ import { transactionGetGasForNetwork, } from "@stakekit/api-hooks"; import { EitherAsync, List } from "purify-ts"; -import { withRequestErrorRetry } from "./utils"; export const getAverageGasMode = ({ network, }: { network: Networks; }) => - withRequestErrorRetry({ fn: () => transactionGetGasForNetwork(network) }) + EitherAsync(() => transactionGetGasForNetwork(network)) .mapLeft(() => new Error("Get gas for network error")) .chain((gas) => EitherAsync.liftEither( diff --git a/packages/widget/src/common/utils.ts b/packages/widget/src/common/utils.ts index 610b8155..16b41beb 100644 --- a/packages/widget/src/common/utils.ts +++ b/packages/widget/src/common/utils.ts @@ -11,9 +11,6 @@ export const isAxios4xxError = (error: unknown): error is AxiosError => error.response?.status < 500 ); -export const shouldRetryRequest = (error: AxiosError) => - !!(error.response?.status && error.response.status >= 500); - const _shouldRetry = ({ error, retryCount, @@ -22,8 +19,15 @@ const _shouldRetry = ({ error: unknown; retryCount: number; retryTimes: number; -}) => - isAxiosError(error) && shouldRetryRequest(error) && retryCount < retryTimes; +}) => { + const res = + isAxiosError(error) && + error?.code !== "ERR_CANCELED" && + (!error.response?.status || error.response.status >= 500) && + retryCount < retryTimes; + + return res; +}; /** * diff --git a/packages/widget/src/hooks/api/use-yield-opportunity.ts b/packages/widget/src/hooks/api/use-yield-opportunity.ts index 87337bdb..09a580e6 100644 --- a/packages/widget/src/hooks/api/use-yield-opportunity.ts +++ b/packages/widget/src/hooks/api/use-yield-opportunity.ts @@ -3,7 +3,6 @@ import type { YieldDto } from "@stakekit/api-hooks"; import type { QueryClient } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query"; import { EitherAsync } from "purify-ts"; -import { withRequestErrorRetry } from "../../common/utils"; import { useSKWallet } from "../../providers/sk-wallet"; type Params = { @@ -61,16 +60,15 @@ const fn = ({ }: Params & { signal?: AbortSignal; }) => - withRequestErrorRetry({ - fn: () => - yieldYieldOpportunity( - yieldId, - { - ledgerWalletAPICompatible: isLedgerLive, - }, - signal - ), - }).mapLeft((e) => { + EitherAsync(() => + yieldYieldOpportunity( + yieldId, + { + ledgerWalletAPICompatible: isLedgerLive, + }, + signal + ) + ).mapLeft((e) => { console.log(e); return new Error("Could not get yield opportunity"); }); diff --git a/packages/widget/src/pages/details/activity-page/activity.page.tsx b/packages/widget/src/pages/details/activity-page/activity.page.tsx index 8651195c..536d9e54 100644 --- a/packages/widget/src/pages/details/activity-page/activity.page.tsx +++ b/packages/widget/src/pages/details/activity-page/activity.page.tsx @@ -2,7 +2,7 @@ import { Box, Text } from "@sk-widget/components"; import { ContentLoaderSquare } from "@sk-widget/components/atoms/content-loader"; import { GroupedVirtualList } from "@sk-widget/components/atoms/virtual-list"; import { useTrackPage } from "@sk-widget/hooks/tracking/use-track-page"; -import ActionListItem from "@sk-widget/pages/details/activity-page/components/action-list-item"; +import { ActionListItem } from "@sk-widget/pages/details/activity-page/components/action-list-item"; import ListItemBullet from "@sk-widget/pages/details/activity-page/components/list-item-bullet"; import { ActivityPageContextProvider, @@ -94,7 +94,7 @@ export const ActivityPageComponent = () => { groupCounts={counts} groupContent={(index) => { return ( - + {dateGroupLabels(labels[index], t)} @@ -105,7 +105,15 @@ export const ActivityPageComponent = () => { const item = allData[index]; return ( - + {badgeLabel} @@ -122,5 +125,3 @@ const ActionListItem = ({ ); }; - -export default ActionListItem; diff --git a/packages/widget/src/pages/details/earn-page/state/use-pending-action-deep-link.ts b/packages/widget/src/pages/details/earn-page/state/use-pending-action-deep-link.ts index caec5d66..876c68ec 100644 --- a/packages/widget/src/pages/details/earn-page/state/use-pending-action-deep-link.ts +++ b/packages/widget/src/pages/details/earn-page/state/use-pending-action-deep-link.ts @@ -1,4 +1,3 @@ -import { withRequestErrorRetry } from "@sk-widget/common/utils"; import { PAMultiValidatorsRequired, PASingleValidatorRequired, @@ -86,15 +85,14 @@ const fn = ({ return EitherAsync.liftEither(initQueryParams) .chain((initQueryParams) => - withRequestErrorRetry({ - fn: () => - yieldGetSingleYieldBalances(initQueryParams.yieldId, { - addresses: { - address, - additionalAddresses: additionalAddresses ?? undefined, - }, - }), - }) + EitherAsync(() => + yieldGetSingleYieldBalances(initQueryParams.yieldId, { + addresses: { + address, + additionalAddresses: additionalAddresses ?? undefined, + }, + }) + ) .mapLeft(() => new Error("could not get yield balances")) .map((val) => ({ yieldId: initQueryParams.yieldId, diff --git a/packages/widget/src/pages/position-details/hooks/use-unstake-machine.ts b/packages/widget/src/pages/position-details/hooks/use-unstake-machine.ts index e7441470..be3aa750 100644 --- a/packages/widget/src/pages/position-details/hooks/use-unstake-machine.ts +++ b/packages/widget/src/pages/position-details/hooks/use-unstake-machine.ts @@ -1,4 +1,3 @@ -import { withRequestErrorRetry } from "@sk-widget/common/utils"; import { getValidStakeSessionTx } from "@sk-widget/domain"; import type { SKWallet } from "@sk-widget/domain/types"; import { useSavedRef } from "@sk-widget/hooks"; @@ -168,19 +167,18 @@ const getMachine = ( context.data.toEither(new Error("Missing init values")) ) .chain((val) => - withRequestErrorRetry({ - fn: () => - transactionGetTransactionVerificationMessageForNetwork( - val.network, - { - addresses: { - address: val.address, - additionalAddresses: - val.additionalAddresses ?? undefined, - }, - } - ), - }).mapLeft( + EitherAsync(() => + transactionGetTransactionVerificationMessageForNetwork( + val.network, + { + addresses: { + address: val.address, + additionalAddresses: + val.additionalAddresses ?? undefined, + }, + } + ) + ).mapLeft( () => new Error("Failed to get verification message") ) ) @@ -297,9 +295,7 @@ const getMachine = ( .toEither(new Error("Missing params")) ) .chain((val) => - withRequestErrorRetry({ - fn: () => actionExit(val), - }) + EitherAsync(() => actionExit(val)) .mapLeft(() => new Error("Stake exit error")) .chain((actionDto) => EitherAsync.liftEither(getValidStakeSessionTx(actionDto)) diff --git a/packages/widget/src/pages/review/hooks/use-pending-review.hook.ts b/packages/widget/src/pages/review/hooks/use-pending-review.hook.ts index 069e433c..fe75a870 100644 --- a/packages/widget/src/pages/review/hooks/use-pending-review.hook.ts +++ b/packages/widget/src/pages/review/hooks/use-pending-review.hook.ts @@ -1,4 +1,3 @@ -import { withRequestErrorRetry } from "@sk-widget/common/utils"; import { getValidStakeSessionTx } from "@sk-widget/domain"; import { useGasWarningCheck } from "@sk-widget/hooks/use-gas-warning-check"; import { getRewardTokenSymbols } from "@sk-widget/hooks/use-reward-token-details/get-reward-token-symbols"; @@ -118,9 +117,7 @@ export const usePendingActionReview = () => { const actionPendingMutation = useMutation({ mutationFn: async () => ( - await withRequestErrorRetry({ - fn: () => actionPending(pendingRequest.requestDto), - }) + await EitherAsync(() => actionPending(pendingRequest.requestDto)) .mapLeft(() => new Error("Pending actions error")) .chain((actionDto) => EitherAsync.liftEither(getValidStakeSessionTx(actionDto)) diff --git a/packages/widget/src/pages/review/hooks/use-stake-review.hook.ts b/packages/widget/src/pages/review/hooks/use-stake-review.hook.ts index bc9700be..138394a2 100644 --- a/packages/widget/src/pages/review/hooks/use-stake-review.hook.ts +++ b/packages/widget/src/pages/review/hooks/use-stake-review.hook.ts @@ -1,4 +1,3 @@ -import { withRequestErrorRetry } from "@sk-widget/common/utils"; import { getValidStakeSessionTx } from "@sk-widget/domain"; import { useSavedRef, useTokensPrices } from "@sk-widget/hooks"; import { useEstimatedRewards } from "@sk-widget/hooks/use-estimated-rewards"; @@ -124,9 +123,7 @@ export const useStakeReview = () => { const enterMutation = useMutation({ mutationFn: async () => ( - await withRequestErrorRetry({ - fn: () => actionEnter(enterRequest.requestDto), - }) + await EitherAsync(() => actionEnter(enterRequest.requestDto)) .mapLeft((e) => { if ( isAxiosError(e) && diff --git a/packages/widget/src/pages/steps/hooks/use-steps-machine.hook.ts b/packages/widget/src/pages/steps/hooks/use-steps-machine.hook.ts index 77e2cdf9..751e4d4c 100644 --- a/packages/widget/src/pages/steps/hooks/use-steps-machine.hook.ts +++ b/packages/widget/src/pages/steps/hooks/use-steps-machine.hook.ts @@ -359,12 +359,11 @@ const getMachine = ( ) .chain((currentTx) => { if (currentTx.meta.broadcasted) { - return withRequestErrorRetry({ - fn: () => - transactionSubmitHash(currentTx.tx.id, { - hash: currentTx.meta.signedTx!, - }), - }) + return EitherAsync(() => + transactionSubmitHash(currentTx.tx.id, { + hash: currentTx.meta.signedTx!, + }) + ) .mapLeft(() => new SubmitHashError()) .ifRight(() => { ref.current.trackEvent("txSubmitted", { @@ -372,16 +371,15 @@ const getMachine = ( network: currentTx.tx.network, yieldId: context.yieldId, }); - }); + }) + .void(); } - return withRequestErrorRetry({ - fn: async () => { - await transactionSubmit(currentTx.tx.id, { - signedTransaction: currentTx.meta.signedTx!, - }); - }, - }) + return EitherAsync(() => + transactionSubmit(currentTx.tx.id, { + signedTransaction: currentTx.meta.signedTx!, + }) + ) .mapLeft(() => new SubmitError()) .ifRight(() => { ref.current.trackEvent("txSubmitted", { @@ -389,7 +387,8 @@ const getMachine = ( network: currentTx.tx.network, yieldId: context.yieldId, }); - }); + }) + .void(); }) .caseOf({ Left: (l) => { @@ -456,13 +455,13 @@ const getMachine = ( shouldRetry: (e, retryCount) => retryCount <= 3 && isAxiosError(e) && - (e.response?.status === 404 || e.response?.status === 503), + e.response?.status === 404, }) .map((res) => ({ url: res.url, status: res.status })) .chainLeft(() => - withRequestErrorRetry({ - fn: () => transactionGetTransaction(currentTx.tx.id), - }).map((res) => ({ + EitherAsync(() => + transactionGetTransaction(currentTx.tx.id) + ).map((res) => ({ url: res.explorerUrl, status: res.status, })) diff --git a/packages/widget/src/providers/api/api-client-provider.tsx b/packages/widget/src/providers/api/api-client-provider.tsx index a8baf304..44b0ede3 100644 --- a/packages/widget/src/providers/api/api-client-provider.tsx +++ b/packages/widget/src/providers/api/api-client-provider.tsx @@ -1,3 +1,4 @@ +import { withRequestErrorRetry } from "@sk-widget/common/utils"; import { StakeKitApiClient } from "@stakekit/api-hooks"; import type { AxiosInstance } from "axios"; import axios, { AxiosHeaders } from "axios"; @@ -44,12 +45,17 @@ export const SKApiClientProvider = ({ children }: PropsWithChildren) => { const signal = requestInit.signal ?? undefined; - return apiClient(url, { - ...requestInit, - headers: axiosHeaders, - data: requestInit.body, - signal, - }).then((response) => response.data); + return withRequestErrorRetry({ + fn: () => + apiClient(url, { + ...requestInit, + headers: axiosHeaders, + data: requestInit.body, + signal, + }).then((response) => response.data), + }) + .run() + .then((res) => res.unsafeCoerce()); }, }); diff --git a/packages/widget/src/providers/query-client/index.tsx b/packages/widget/src/providers/query-client/index.tsx index 1f121099..2971d8ed 100644 --- a/packages/widget/src/providers/query-client/index.tsx +++ b/packages/widget/src/providers/query-client/index.tsx @@ -1,9 +1,7 @@ import { QueryClient } from "@tanstack/react-query"; import { QueryClientProvider } from "@tanstack/react-query"; -import { isAxiosError } from "axios"; import type { PropsWithChildren } from "react"; import { createContext, useContext, useState } from "react"; -import { shouldRetryRequest } from "../../common/utils"; import { config } from "../../config"; const getQueryClient = () => @@ -12,24 +10,10 @@ const getQueryClient = () => queries: { gcTime: config.queryClient.cacheTime, staleTime: config.queryClient.staleTime, - retry: (failureCount, error) => { - if (isAxiosError(error)) { - return !!(shouldRetryRequest(error) && failureCount < 2); - } - - return false; - }, + retry: false, refetchOnWindowFocus: false, }, - mutations: { - retry: (failureCount, error) => { - if (isAxiosError(error)) { - return !!(shouldRetryRequest(error) && failureCount < 2); - } - - return false; - }, - }, + mutations: { retry: false }, }, }); diff --git a/packages/widget/src/translation/index.ts b/packages/widget/src/translation/index.ts index 3ae3e025..ad572a12 100644 --- a/packages/widget/src/translation/index.ts +++ b/packages/widget/src/translation/index.ts @@ -1,8 +1,8 @@ import { useQuery } from "@tanstack/react-query"; import { createInstance } from "i18next"; import LanguageDetector from "i18next-browser-languagedetector"; +import { EitherAsync } from "purify-ts"; import { initReactI18next, useTranslation } from "react-i18next"; -import { withRequestErrorRetry } from "../common/utils"; import { useApiClient } from "../providers/api/api-client-provider"; import translationEN from "./English/translations.json"; import translationFR from "./French/translations.json"; @@ -42,16 +42,17 @@ export const useLoadErrorTranslations = () => { queryKey: ["error-translations", lng], staleTime: Number.POSITIVE_INFINITY, gcTime: Number.POSITIVE_INFINITY, - queryFn: () => - withRequestErrorRetry({ - fn: () => + queryFn: async () => + ( + await EitherAsync(() => apiClient.get>( `https://i18n.stakek.it/locales/${lng}/errors.json` - ), - }).ifRight((res) => - i18n.addResourceBundle(i18n.language, "translation", { - errors: res.data, - }) - ), + ) + ).ifRight((res) => + i18n.addResourceBundle(i18n.language, "translation", { + errors: res.data, + }) + ) + ).unsafeCoerce(), }); };