diff --git a/.gitignore b/.gitignore index d19457bb13..b39dd7e787 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,4 @@ coverage /.cache # Nix -result* +result diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/staking/components/MultiDelegationStaking.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/staking/components/MultiDelegationStaking.tsx index 552fb879ad..673c9a80da 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/staking/components/MultiDelegationStaking.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/staking/components/MultiDelegationStaking.tsx @@ -24,7 +24,7 @@ export const MultiDelegationStaking = (): JSX.Element => { selectedStakePool } = useDelegationStore(); const openExternalLink = useExternalLinkOpener(); - const { password, setPassword, removePassword } = usePassword(); + const password = usePassword(); const submittingState = useSubmitingState(); const { priceResult } = useFetchCoinPrice(); const { balance } = useBalances(priceResult?.cardano?.price); @@ -53,16 +53,13 @@ export const MultiDelegationStaking = (): JSX.Element => { fetchCoinPricePriceResult: priceResult, openExternalLink, password, - setPassword, - passwordRemovePassword: removePassword, - passwordSetPassword: setPassword, stakingRewards, submittingState, walletStoreGetKeyAgentType: getKeyAgentType, walletStoreInMemoryWallet: inMemoryWallet, walletStoreWalletUICardanoCoin: cardanoCoin, currencyStoreFiatCurrency: fiatCurrency, - executeWithPassword + walletManagerExecuteWithPassword: executeWithPassword }} > diff --git a/packages/staking/src/features/drawer/ResultMessage.module.scss b/packages/staking/src/features/drawer/ResultMessage.module.scss new file mode 100644 index 0000000000..0e600a1211 --- /dev/null +++ b/packages/staking/src/features/drawer/ResultMessage.module.scss @@ -0,0 +1,60 @@ +@import '../../../../../packages/common/src/ui/styles/theme.scss'; +@import '../../../../../packages/common/src/ui/styles/abstracts/typography'; + +.content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: size_unit(4); + + .title { + color: var(--text-color-primary); + font-size: var(--heading); + font-weight: 700; + line-height: size_unit(5); + letter-spacing: -0.015em; + text-align: center; + margin-bottom: 0 !important; + + max-width: 435px; + + @media (max-width: $breakpoint-popup) { + font-size: var(--heading); + line-height: size_unit(4); + margin-bottom: 0; + } + } + + .description { + color: var(--text-color-secondary) !important; + font-size: var(--body); + font-weight: 500; + line-height: size_unit(3); + text-align: center; + margin-bottom: 0 !important; + max-width: 450px; + padding: 10px; + + @media (max-width: $breakpoint-popup) { + max-width: 260px; + padding: 0; + font-size: var(--body); + line-height: size_unit(3); + margin-bottom: 0; + } + } + .vertical { + display: flex; + flex-direction: column; + align-items: center; + gap: size_unit(2); + } + .img { + height: size_unit(14); + width: size_unit(14); + @media (max-width: $breakpoint-popup) { + width: size_unit(11); + } + } +} diff --git a/packages/staking/src/features/drawer/ResultMessage.tsx b/packages/staking/src/features/drawer/ResultMessage.tsx new file mode 100644 index 0000000000..95b5375a4d --- /dev/null +++ b/packages/staking/src/features/drawer/ResultMessage.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import ExclamationSmall from './exclamation-circle-small.svg'; +import Exclamation from './exclamation-circle.svg'; +import styles from './ResultMessage.module.scss'; +import Success from './success-staking.svg'; + +type Status = 'success' | 'error'; + +const iconByStatus: Record>> = { + error: Exclamation, + success: Success, +}; + +// TODO discuss with design team if we can have 1 error icon and just manipulate its size +const popupViewIconByStatus: Record>> = { + ...iconByStatus, + error: ExclamationSmall, +}; + +export interface ResultMessageProps { + status?: Status; + title: React.ReactNode; + description: React.ReactNode; + popupView?: boolean; +} + +export const ResultMessage = ({ + status = 'success', + title, + description, + popupView, +}: ResultMessageProps): React.ReactElement => { + const Icon = popupView ? popupViewIconByStatus[status] : iconByStatus[status]; + + return ( +
+ +
+

+ {title} +

+
+ {description} +
+
+
+ ); +}; diff --git a/packages/staking/src/features/drawer/SignConfirmation.tsx b/packages/staking/src/features/drawer/SignConfirmation.tsx index c834a65674..eeb0097d39 100644 --- a/packages/staking/src/features/drawer/SignConfirmation.tsx +++ b/packages/staking/src/features/drawer/SignConfirmation.tsx @@ -4,7 +4,7 @@ import cn from 'classnames'; import React, { ReactElement, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useOutsideHandles } from '../outside-handles-provider'; -import { useDelegationPortfolioStore, useStakePoolDetails } from '../store'; +import { Sections, sectionsConfig, useDelegationPortfolioStore, useStakePoolDetails } from '../store'; import styles from './SignConfirmation.module.scss'; interface SignConfirmationProps { @@ -14,8 +14,7 @@ interface SignConfirmationProps { export const SignConfirmation = ({ popupView }: SignConfirmationProps): React.ReactElement => { const { t } = useTranslation(); const { - password, - passwordSetPassword: setPassword, + password: { password, setPassword }, submittingState: { isPasswordValid }, } = useOutsideHandles(); @@ -54,19 +53,18 @@ export const SignConfirmation = ({ popupView }: SignConfirmationProps): React.Re export const SignConfirmationFooter = ({ popupView }: SignConfirmationProps): ReactElement => { const { walletStoreInMemoryWallet: inMemoryWallet, - password, - passwordRemovePassword: removePassword, + password: { password, removePassword }, submittingState: { setSubmitingTxState, isSubmitingTx, setIsRestaking }, delegationStoreDelegationTxBuilder: delegationTxBuilder, delegationDetails, - executeWithPassword, + walletManagerExecuteWithPassword: executeWithPassword, } = useOutsideHandles(); const { draftPortfolio, portfolioMutators } = useDelegationPortfolioStore((store) => ({ draftPortfolio: store.draftPortfolio, portfolioMutators: store.mutators, })); const { t } = useTranslation(); - const { setPrevSection, setIsDrawerVisible } = useStakePoolDetails(); + const { setSection } = useStakePoolDetails(); const rewardAccounts = useObservable(inMemoryWallet.delegation.rewardAccounts$); const isDelegating = !!(rewardAccounts && (delegationDetails || draftPortfolio.length > 0)); @@ -106,12 +104,8 @@ export const SignConfirmationFooter = ({ popupView }: SignConfirmationProps): Re cleanPasswordInput(); sendAnalytics(); setIsRestaking(isDelegating); - // v TODO replace this block with setSection(sectionsConfig[Sections.SUCCESS_TX]); when Success section is implemented - setIsDrawerVisible(false); - setPrevSection(); - setPrevSection(); portfolioMutators.clearDraft(); - // ^ TODO replace this block with setSection(sectionsConfig[Sections.SUCCESS_TX]); when Success section is implemented + setSection(sectionsConfig[Sections.SUCCESS_TX]); setSubmitingTxState({ isPasswordValid: true, isSubmitingTx: false }); } catch (error) { // Error name is 'AuthenticationError' in dev build but 'W' in prod build @@ -119,11 +113,20 @@ export const SignConfirmationFooter = ({ popupView }: SignConfirmationProps): Re if (error.message?.includes('Authentication failure')) { setSubmitingTxState({ isPasswordValid: false, isSubmitingTx: false }); } else { - // setSection(sectionsConfig[Sections.FAIL_TX]); + setSection(sectionsConfig[Sections.FAIL_TX]); setSubmitingTxState({ isSubmitingTx: false }); } } - }, [setSubmitingTxState, signAndSubmitTransaction, cleanPasswordInput, sendAnalytics, setIsRestaking, isDelegating]); + }, [ + setSubmitingTxState, + signAndSubmitTransaction, + cleanPasswordInput, + sendAnalytics, + setIsRestaking, + isDelegating, + portfolioMutators, + setSection, + ]); return (
diff --git a/packages/staking/src/features/drawer/StakePoolDetails.tsx b/packages/staking/src/features/drawer/StakePoolDetails.tsx index 199baafe51..fd75c20cbe 100644 --- a/packages/staking/src/features/drawer/StakePoolDetails.tsx +++ b/packages/staking/src/features/drawer/StakePoolDetails.tsx @@ -7,6 +7,8 @@ import { SignConfirmation, SignConfirmationFooter } from './SignConfirmation'; import { StakePoolConfirmation, StakePoolConfirmationFooter } from './StakePoolConfirmation'; import { StakePoolDetail, StakePoolDetailFooter } from './StakePoolDetail'; import { StakePoolDetailsDrawer } from './StakePoolDetailsDrawer'; +import { TransactionFail, TransactionFailFooter } from './TransactionFail'; +import { TransactionSuccess, TransactionSuccessFooter } from './TransactionSuccess'; type stakePoolDetailsProps = { onStake: () => void; @@ -38,8 +40,8 @@ export const StakePoolDetails = ({ [Sections.DETAIL]: , [Sections.CONFIRMATION]: , [Sections.SIGN]: , - [Sections.SUCCESS_TX]:
, - [Sections.FAIL_TX]:
, + [Sections.SUCCESS_TX]: , + [Sections.FAIL_TX]: , }), [] ); @@ -49,8 +51,8 @@ export const StakePoolDetails = ({ [Sections.DETAIL]: , [Sections.CONFIRMATION]: , [Sections.SIGN]: , - [Sections.SUCCESS_TX]:
, - [Sections.FAIL_TX]:
, + [Sections.SUCCESS_TX]: , + [Sections.FAIL_TX]: , }), [onStake, canDelegate] ); diff --git a/packages/staking/src/features/drawer/StakePoolDetailsDrawer.tsx b/packages/staking/src/features/drawer/StakePoolDetailsDrawer.tsx index 5d456fbb97..2ffe9aa863 100644 --- a/packages/staking/src/features/drawer/StakePoolDetailsDrawer.tsx +++ b/packages/staking/src/features/drawer/StakePoolDetailsDrawer.tsx @@ -36,8 +36,7 @@ export const StakePoolDetailsDrawer = ({ backgroundServiceAPIContextSetWalletPassword, delegationStoreSetDelegationTxBuilder, walletStoreGetKeyAgentType, - password, - passwordRemovePassword, + password: { password, removePassword }, submittingState: { setIsRestaking }, } = useOutsideHandles(); @@ -53,7 +52,7 @@ export const StakePoolDetailsDrawer = ({ backgroundServiceAPIContextSetWalletPassword(); delegationStoreSetDelegationTxBuilder(); resetStates(); - passwordRemovePassword(); + removePassword(); // TODO: Remove this once we pay the `keyAgent.signTransaction` Ledger tech debt up (so we are able to stake multiple times without reloading). // if (!isInMemory && isSuccessSection) window.location.reload(); setIsDrawerVisible(false); @@ -66,7 +65,7 @@ export const StakePoolDetailsDrawer = ({ backgroundServiceAPIContextSetWalletPassword, delegationStoreSetDelegationTxBuilder, resetStates, - passwordRemovePassword, + removePassword, // isInMemory, // isSuccessSection, setIsDrawerVisible, @@ -76,7 +75,7 @@ export const StakePoolDetailsDrawer = ({ const onArrowIconClick = useCallback(() => { if (password) { backgroundServiceAPIContextSetWalletPassword(); - passwordRemovePassword(); + removePassword(); } if (simpleSendConfig.currentSection === Sections.CONFIRMATION && !isInMemory) { return setSection(sectionsConfig[Sections.DETAIL]); @@ -89,7 +88,7 @@ export const StakePoolDetailsDrawer = ({ closeDrawer, isInMemory, password, - passwordRemovePassword, + removePassword, setPrevSection, setSection, simpleSendConfig.currentSection, diff --git a/packages/staking/src/features/drawer/TransactionComplete.module.scss b/packages/staking/src/features/drawer/TransactionComplete.module.scss new file mode 100644 index 0000000000..8b8d6ec78f --- /dev/null +++ b/packages/staking/src/features/drawer/TransactionComplete.module.scss @@ -0,0 +1,84 @@ +@import '../../../../../packages/common/src/ui/styles/theme.scss'; + +.container { + display: flex; + flex-direction: column; + justify-content: center; + height: 100%; +} + +.header { + .title { + align-items: center; + color: var(--text-color-black); + display: flex; + font-size: var(--heading); + font-weight: bold; + line-height: size_unit(4); + } + .subTitle { + color: var(--text-color-secondary); + font-size: var(--bodyLarge); + font-weight: 600; + line-height: size_unit(3); + margin-top: size_unit(2); + } +} + +.password { + display: flex; + justify-content: center; +} + +.footer { + .confirmBtn { + width: 100%; + } +} + +.footerFail { + display: flex; + gap: size_unit(2); + justify-content: space-between; + flex-direction: column-reverse; +} + +.popupView { + &.container { + .header { + padding-left: size_unit(3); + padding-right: size_unit(3); + .title { + font-weight: 700; + font-size: var(-subHeading); + line-height: size_unit(4); + } + .subTitle { + font-size: var(--body); + margin-top: size_unit(2); + } + } + img { + max-width: initial; + max-height: initial; + } + &.fail { + img { + width: 100px; + max-width: initial; + } + } + .footer, + .footerFail { + box-shadow: 0px -2px 4px rgba(0, 0, 0, 0.05); + padding: size_unit(2) size_unit(3) 0px size_unit(3); + } + } +} + +.containerFail { + display: flex; + align-items: center; + height: 80%; + justify-content: center; +} diff --git a/packages/staking/src/features/drawer/TransactionFail.tsx b/packages/staking/src/features/drawer/TransactionFail.tsx new file mode 100644 index 0000000000..4eb67bc0f0 --- /dev/null +++ b/packages/staking/src/features/drawer/TransactionFail.tsx @@ -0,0 +1,114 @@ +/* eslint-disable react/no-multi-comp */ +import { Button } from '@lace/common'; +import cn from 'classnames'; +import React, { useCallback, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useOutsideHandles } from '../outside-handles-provider'; +import { Sections, sectionsConfig, useStakePoolDetails } from '../store'; +import { ResultMessage } from './ResultMessage'; +import styles from './TransactionComplete.module.scss'; + +type TransactionFailProps = { + popupView?: boolean; +}; + +export const TransactionFail = ({ popupView }: TransactionFailProps): React.ReactElement => { + const { t } = useTranslation(); + + return ( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion +
+
+ +
+
+ ); +}; + +export const TransactionFailFooter = ({ popupView }: TransactionFailProps): React.ReactElement => { + const { t } = useTranslation(); + const [isLoading, setIsLoading] = useState(false); + const { setIsDrawerVisible, resetStates, setSection } = useStakePoolDetails(); + const { + walletManagerExecuteWithPassword: executeWithPassword, + delegationStoreSetDelegationTxBuilder: setDelegationTxBuilder, + delegationStoreDelegationTxBuilder: delegationTxBuilder, + password: { password, removePassword }, + walletStoreInMemoryWallet: inMemoryWallet, + } = useOutsideHandles(); + // TODO implement analytics for the new flow + const analytics = { + // eslint-disable-next-line @typescript-eslint/no-empty-function + sendEvent: () => {}, + }; + + const closeDrawer = () => { + // @ts-ignore + analytics.sendEvent({ + action: 'AnalyticsEventActions.CLICK_EVENT', + category: 'AnalyticsEventCategories.STAKING', + name: popupView + ? 'AnalyticsEventNames.Staking.STAKING_FAIL_POPUP' + : 'AnalyticsEventNames.Staking.STAKING_FAIL_BROWSER', + }); + setDelegationTxBuilder(); + setIsDrawerVisible(false); + resetStates(); + }; + + // TODO unify + const signAndSubmitTransaction = useCallback(async () => { + if (!delegationTxBuilder) throw new Error('Unable to submit transaction. The delegationTxBuilder not available'); + const signedTx = await delegationTxBuilder.build().sign(); + await inMemoryWallet.submitTx(signedTx.tx); + }, [delegationTxBuilder, inMemoryWallet]); + + const onSubmit = async () => { + setIsLoading(true); + try { + await signAndSubmitTransaction(); + setIsLoading(false); + setSection(sectionsConfig[Sections.SUCCESS_TX]); + removePassword(); + } catch (error) { + console.error('failed to sign or submit tx due to:', error); + setIsLoading(false); + } + }; + + return ( +
+ + {popupView ? ( + + ) : ( + + )} +
+ ); +}; diff --git a/packages/staking/src/features/drawer/TransactionSuccess.tsx b/packages/staking/src/features/drawer/TransactionSuccess.tsx new file mode 100644 index 0000000000..5271e809e4 --- /dev/null +++ b/packages/staking/src/features/drawer/TransactionSuccess.tsx @@ -0,0 +1,73 @@ +/* eslint-disable react/no-multi-comp */ +import { Wallet } from '@lace/cardano'; +import { Button } from '@lace/common'; +import cn from 'classnames'; +import React, { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useOutsideHandles } from '../outside-handles-provider'; +import { useStakePoolDetails } from '../store'; +import { ResultMessage } from './ResultMessage'; +import styles from './TransactionComplete.module.scss'; + +type TransactionSuccessProps = { + popupView?: boolean; +}; + +export const TransactionSuccess = ({ popupView }: TransactionSuccessProps): React.ReactElement => { + const { t } = useTranslation(); + const { + submittingState: { isRestaking }, + } = useOutsideHandles(); + + return ( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion +
+ +
+ ); +}; + +export const TransactionSuccessFooter = ({ popupView }: TransactionSuccessProps): React.ReactElement => { + const { t } = useTranslation(); + const { delegationStoreSetDelegationTxBuilder: setDelegationTxBuilder, walletStoreGetKeyAgentType: getKeyAgentType } = + useOutsideHandles(); + const { setIsDrawerVisible, resetStates } = useStakePoolDetails(); + // TODO implement analytics for the new flow + const analytics = { + // eslint-disable-next-line @typescript-eslint/no-empty-function + sendEvent: () => {}, + }; + const isInMemory = useMemo(() => getKeyAgentType() === Wallet.KeyManagement.KeyAgentType.InMemory, [getKeyAgentType]); + + const closeDrawer = () => { + // @ts-ignore + analytics.sendEvent({ + action: 'AnalyticsEventActions.CLICK_EVENT', + category: 'AnalyticsEventCategories.STAKING', + name: popupView + ? 'AnalyticsEventNames.Staking.STAKING_SUCCESS_POPUP' + : 'AnalyticsEventNames.Staking.STAKING_SUCCESS_BROWSER', + }); + setDelegationTxBuilder(); + setIsDrawerVisible(false); + resetStates(); + // TODO: Remove this once we pay the `keyAgent.signTransaction` Ledger tech debt up (so we are able to stake multiple times without reloading). + if (!isInMemory) window.location.reload(); + }; + + return ( +
+ +
+ ); +}; diff --git a/packages/staking/src/features/drawer/exclamation-circle.svg b/packages/staking/src/features/drawer/exclamation-circle.svg new file mode 100644 index 0000000000..c245b27003 --- /dev/null +++ b/packages/staking/src/features/drawer/exclamation-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/staking/src/features/drawer/success-staking.svg b/packages/staking/src/features/drawer/success-staking.svg new file mode 100644 index 0000000000..f190d5c768 --- /dev/null +++ b/packages/staking/src/features/drawer/success-staking.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/staking/src/features/i18n/translations/en.ts b/packages/staking/src/features/i18n/translations/en.ts index f4701b2ac2..a96e51870e 100644 --- a/packages/staking/src/features/i18n/translations/en.ts +++ b/packages/staking/src/features/i18n/translations/en.ts @@ -42,12 +42,23 @@ export const en: Translations = { 'drawer.details.switchingPoolBanner.description.step3': 'Follow the instructions in the staking flow', 'drawer.details.switchingPoolBanner.title': 'Unstaking is not yet available. Follow these steps if you wish to change stake pool', + 'drawer.failure.button.back': 'Back', + 'drawer.failure.button.close': 'Close', + 'drawer.failure.button.retry': 'Retry', + 'drawer.failure.subTitle': 'The transaction was not successful. Please try again.', + 'drawer.failure.title': 'Oops! Something went wrong...', 'drawer.sign.confirmation.title': 'Staking confirmation', 'drawer.sign.enterWalletPasswordToConfirmTransaction': 'Enter your wallet password to confirm transaction', 'drawer.sign.error.invalidPassword': 'Wrong password', 'drawer.sign.passwordPlaceholder': 'Password', + 'drawer.success.subTitle': "You'll start receiving your staking rewards after two epochs.", + 'drawer.success.switchedPools.subTitle': + "You'll start receiving your staking rewards from the new pool after two epochs. Until then you'll continue receiving rewards from the previous one.", + 'drawer.success.switchedPools.title': "Hurray! You've switched pools", + 'drawer.success.title': "Hurray! You've staked your funds", 'drawer.title': 'Stake pool detail', 'drawer.titleSecond': 'Manage delegation', + 'general.button.close': 'Close', 'general.button.confirm': 'Confirm', 'overview.delegationCard.label.balance': 'Balance', 'overview.delegationCard.label.pools': 'Pool(s)', diff --git a/packages/staking/src/features/i18n/types.ts b/packages/staking/src/features/i18n/types.ts index 0e7a9b27ea..13b399d081 100644 --- a/packages/staking/src/features/i18n/types.ts +++ b/packages/staking/src/features/i18n/types.ts @@ -12,6 +12,7 @@ type KeysStructure = { general: { button: { confirm: ''; + close: ''; }; }; browsePools: { @@ -39,6 +40,23 @@ type KeysStructure = { invalidPassword: ''; }; }; + success: { + title: ''; + subTitle: ''; + switchedPools: { + title: ''; + subTitle: ''; + }; + }; + failure: { + title: ''; + subTitle: ''; + button: { + close: ''; + back: ''; + retry: ''; + }; + }; details: { metrics: { activeStake: ''; diff --git a/packages/staking/src/features/outside-handles-provider/types.ts b/packages/staking/src/features/outside-handles-provider/types.ts index 6a6af1b7b2..5cd3e2f27a 100644 --- a/packages/staking/src/features/outside-handles-provider/types.ts +++ b/packages/staking/src/features/outside-handles-provider/types.ts @@ -42,6 +42,12 @@ export interface SubmittingState { isPasswordValid?: boolean; } +export interface PasswordHook { + password?: string; + setPassword: (pass: string) => void; + removePassword: () => void; +} + export type OutsideHandlesContextValue = { backgroundServiceAPIContextSetWalletPassword: (password?: Uint8Array) => void; balancesBalance: Balance; @@ -64,13 +70,15 @@ export type OutsideHandlesContextValue = { }; }; openExternalLink: (href: string) => void; - password?: string; - passwordSetPassword: (password: string) => void; - passwordRemovePassword: () => void; + password: PasswordHook; submittingState: SubmittingState; walletStoreGetKeyAgentType: () => string; walletStoreInMemoryWallet: Wallet.ObservableWallet; walletStoreWalletUICardanoCoin: Wallet.CoinId; + walletManagerExecuteWithPassword: ( + password: string, + promiseFn: () => Promise, + cleanPassword?: boolean + ) => Promise; currencyStoreFiatCurrency: CurrencyInfo; - executeWithPassword: (password: string, promiseFn: () => Promise, cleanPassword?: boolean) => Promise; }; diff --git a/packages/staking/src/features/store/stakingStore.ts b/packages/staking/src/features/store/stakingStore.ts index d166ad55c1..0b76fd68f2 100644 --- a/packages/staking/src/features/store/stakingStore.ts +++ b/packages/staking/src/features/store/stakingStore.ts @@ -1,7 +1,7 @@ import create from 'zustand'; import { SectionConfig, Sections, StakePoolDetails, StakingError } from './types'; -export const sectionsConfig: Record = { +export const sectionsConfig = { [Sections.DETAIL]: { currentSection: Sections.DETAIL, nextSection: Sections.CONFIRMATION, @@ -24,7 +24,7 @@ export const sectionsConfig: Record = { currentSection: Sections.FAIL_TX, prevSection: Sections.SIGN, }, -}; +} as const; const storeDefaultState: Pick = { simpleSendConfig: sectionsConfig[Sections.DETAIL], @@ -54,12 +54,18 @@ export const useStakePoolDetails = create((set, get) => ({ set({ simpleSendConfig: sectionsConfig[prevSection] }); }, setSection: (section?: SectionConfig) => { + if (section) { + set({ simpleSendConfig: section }); + return; + } + const { currentSection, nextSection } = get().simpleSendConfig; if (!nextSection) { - console.error(`Tried to move to not existing section (previous of ${currentSection})`); + console.error(`useStakePoolDetails::setSection: missing nextSection config for section: "${currentSection}"`); return; } - set({ simpleSendConfig: section ?? sectionsConfig[nextSection] }); + + set({ simpleSendConfig: sectionsConfig[nextSection] }); }, setStakeConfirmationVisible: (visibility: boolean) => set({ isStakeConfirmationVisible: visibility }), setStakingError: (error: StakingError | undefined) => set({ stakingError: error }),