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 }),