Skip to content

Commit

Permalink
Merge branch 'main' into feat
Browse files Browse the repository at this point in the history
  • Loading branch information
EtherWizard33 committed Sep 17, 2024
2 parents ade0024 + d91b916 commit a2e54bf
Show file tree
Hide file tree
Showing 16 changed files with 2,516 additions and 41 deletions.
13 changes: 12 additions & 1 deletion app/components/Nav/Main/MainNavigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ import ConfirmAddAsset from '../../UI/ConfirmAddAsset';
import { AesCryptoTestForm } from '../../Views/AesCryptoTestForm';
import { isTest } from '../../../util/test/utils';
import { selectPermissionControllerState } from '../../../selectors/snaps/permissionController';

import NftDetails from '../../Views/NftDetails';
import NftDetailsFullImage from '../../Views/NftDetails/NFtDetailsFullImage';
import AccountPermissions from '../../../components/Views/AccountPermissions';
import { AccountPermissionsScreens } from '../../../components/Views/AccountPermissions/AccountPermissions.types';
import StakeInputView from '../../UI/Stake/Views/InputView/StakeInputView';

const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
Expand Down Expand Up @@ -685,6 +685,16 @@ const Swaps = () => (
</Stack.Navigator>
);

const Stake = () => (
<Stack.Navigator>
<Stack.Screen
name="Stake"
component={StakeInputView}
options={StakeInputView.navigationOptions}
/>
</Stack.Navigator>
);

const SetPasswordFlow = () => (
<Stack.Navigator>
<Stack.Screen
Expand Down Expand Up @@ -789,6 +799,7 @@ const MainNavigator = () => (
{() => <RampRoutes rampType={RampType.SELL} />}
</Stack.Screen>
<Stack.Screen name="Swaps" component={Swaps} />
<Stack.Screen name="Stake" component={Stake} />
<Stack.Screen
name="SetPasswordFlow"
component={SetPasswordFlow}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@ describe('Staking Earnings', () => {
it('should render correctly', () => {
const { toJSON, getByText } = renderWithProvider(<StakingEarnings />);

expect(getByText(strings('staking.your_earnings'))).toBeDefined();
expect(getByText(strings('staking.annual_rate'))).toBeDefined();
expect(getByText(strings('staking.lifetime_rewards'))).toBeDefined();
expect(
getByText(strings('staking.estimated_annual_earnings')),
).toBeDefined();
expect(getByText(strings('stake.your_earnings'))).toBeDefined();
expect(getByText(strings('stake.annual_rate'))).toBeDefined();
expect(getByText(strings('stake.lifetime_rewards'))).toBeDefined();
expect(getByText(strings('stake.estimated_annual_earnings'))).toBeDefined();
expect(toJSON()).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ exports[`Staking Earnings should render correctly 1`] = `
}
}
>
Est. annual earnings
Estimated annual earnings
</Text>
</View>
<View
Expand Down
12 changes: 6 additions & 6 deletions app/components/UI/AssetOverview/StakingEarnings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ const StakingEarnings = () => {

const onNavigateToTooltipModal = () =>
openTooltipModal(
'Annual Rate',
strings('stake.annual_rate'),
strings('tooltip_modal.reward_rate.tooltip'),
);

if (!isPooledStakingFeatureEnabled()) return <></>;

return (
<View style={styles.stakingEarningsContainer}>
<Title style={styles.title}>{strings('staking.your_earnings')}</Title>
<Title style={styles.title}>{strings('stake.your_earnings')}</Title>
<View>
{/* Annual Rate */}
<View style={styles.keyValueRow}>
Expand All @@ -59,15 +59,15 @@ const StakingEarnings = () => {
variant={TextVariant.BodyMDMedium}
style={styles.keyValuePrimaryText}
>
{strings('staking.annual_rate')}
{strings('stake.annual_rate')}
</Text>
<ButtonIcon
size={ButtonIconSizes.Sm}
iconColor={IconColor.Muted}
iconName={IconName.Info}
accessibilityRole="button"
accessibilityLabel={strings(
'staking.accessibility_labels.stake_annual_rate_tooltip',
'stake.accessibility_labels.stake_annual_rate_tooltip',
)}
onPress={onNavigateToTooltipModal}
/>
Expand All @@ -82,7 +82,7 @@ const StakingEarnings = () => {
variant={TextVariant.BodyMDMedium}
style={styles.keyValuePrimaryText}
>
{strings('staking.lifetime_rewards')}
{strings('stake.lifetime_rewards')}
</Text>
</View>
<View style={styles.keyValueSecondaryText}>
Expand All @@ -101,7 +101,7 @@ const StakingEarnings = () => {
variant={TextVariant.BodyMDMedium}
color={TextColor.Alternative}
>
{strings('staking.estimated_annual_earnings')}
{strings('stake.estimated_annual_earnings')}
</Text>
</View>
<View style={styles.keyValueSecondaryText}>
Expand Down
33 changes: 33 additions & 0 deletions app/components/UI/Navbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1811,3 +1811,36 @@ export const getSettingsNavigationOptions = (title, themeColors) => {
...innerStyles,
};
};

export function getStakeInputNavbar(navigation, themeColors) {
const innerStyles = StyleSheet.create({
headerButtonText: {
color: themeColors.primary.default,
fontSize: 14,
...fontStyles.normal,
},
headerStyle: {
backgroundColor: themeColors.background.default,
shadowColor: importedColors.transparent,
elevation: 0,
},
});
const title = strings('stake.stake_eth');
return {
headerTitle: () => (
<NavbarTitle title={title} disableNetwork translate={false} />
),
headerLeft: () => <View />,
headerRight: () => (
<TouchableOpacity
onPress={() => navigation.dangerouslyGetParent()?.pop()}
style={styles.closeButton}
>
<Text style={innerStyles.headerButtonText}>
{strings('navigation.cancel')}
</Text>
</TouchableOpacity>
),
headerStyle: innerStyles.headerStyle,
};
}
50 changes: 50 additions & 0 deletions app/components/UI/Stake/Views/InputView/StakeInputView.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { StyleSheet } from 'react-native';
import type { Theme } from '../../../../../util/theme/models';

const styleSheet = (params: { theme: Theme }) => {
const { theme } = params;
const { colors } = theme;

return StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.background.default,
flexDirection: 'column',
justifyContent: 'center',
},
inputContainer: {
flex: 1,
backgroundColor: colors.background.default,
justifyContent: 'center',
flexDirection: 'column',
alignItems: 'center',
gap: 16,
},
amountRow: {
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row',
gap: 4,
},
amountContainer: {
alignItems: 'center',
},
stakeButtonText: {
fontSize: 18,
color: colors.text.alternative,
},
rewardsRateContainer: {
padding: 16,
paddingBottom: 8,
borderColor: colors.border.muted,
},
reviewButtonContainer: {
padding: 16,
},
keypad: {
paddingHorizontal: 24,
},
});
};

export default styleSheet;
131 changes: 131 additions & 0 deletions app/components/UI/Stake/Views/InputView/StakeInputView.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import React from 'react';
import { fireEvent, screen } from '@testing-library/react-native';
import StakeInputView from './StakeInputView';
import { renderScreen } from '../../../../../util/test/renderWithProvider';
import Routes from '../../../../../constants/navigation/Routes';
import { backgroundState } from '../../../../../util/test/initial-root-state';
import { BN } from 'ethereumjs-util';

function render(Component: React.ComponentType) {
return renderScreen(
Component,
{
name: Routes.STAKE.STAKE,
},
{
state: {
engine: {
backgroundState,
},
},
},
);
}

const mockSetOptions = jest.fn();
const mockNavigate = jest.fn();
const mockReset = jest.fn();
const mockPop = jest.fn();

jest.mock('@react-navigation/native', () => {
const actualReactNavigation = jest.requireActual('@react-navigation/native');
return {
...actualReactNavigation,
useNavigation: () => ({
navigate: mockNavigate,
setOptions: mockSetOptions.mockImplementation(
actualReactNavigation.useNavigation().setOptions,
),
reset: mockReset,
dangerouslyGetParent: () => ({
pop: mockPop,
}),
}),
};
});

// Mock necessary modules and hooks
jest.mock('../../../../../selectors/currencyRateController.ts', () => ({
selectConversionRate: jest.fn(() => 2000),
selectCurrentCurrency: jest.fn(() => 'USD'),
}));

const mockBalanceBN = new BN('1500000000000000000');
jest.mock('../../hooks/useBalance', () => ({
__esModule: true,
default: () => ({
balance: '1.5',
balanceBN: mockBalanceBN,
balanceFiatNumber: '3000',
}),
}));

describe('StakeInputView', () => {
it('render matches snapshot', () => {
render(StakeInputView);
expect(screen.toJSON()).toMatchSnapshot();
});

describe('when values are entered in the keypad', () => {
it('updates ETH and fiat values', () => {
render(StakeInputView);

fireEvent.press(screen.getByText('2'));

expect(screen.getByText('4000 USD')).toBeTruthy();
});
});

describe('currency toggle functionality', () => {
it('switches between ETH and fiat correctly', () => {
render(StakeInputView);

expect(screen.getByText('ETH')).toBeTruthy();
fireEvent.press(screen.getByText('0 USD'));

expect(screen.getByText('USD')).toBeTruthy();
});
});

describe('when calculating rewards', () => {
it('calculates estimated annual rewards based on input', () => {
render(StakeInputView);

fireEvent.press(screen.getByText('2'));

expect(screen.getByText('0.052 ETH')).toBeTruthy();
});
});

describe('quick amount buttons', () => {
it('handles 25% quick amount button press correctly', () => {
render(StakeInputView);

fireEvent.press(screen.getByText('25%'));

expect(screen.getByText('0.375')).toBeTruthy();
});
});

describe('stake button states', () => {
it('displays `Enter amount` if input is 0', () => {
render(StakeInputView);

expect(screen.getByText('Enter amount')).toBeTruthy();
});

it('displays `Review` on stake button if input is valid', () => {
render(StakeInputView);

fireEvent.press(screen.getByText('1'));
expect(screen.getByText('Review')).toBeTruthy();
});

it('displays `Not enough ETH` when input exceeds balance', () => {
render(StakeInputView);

fireEvent.press(screen.getByText('4'));
expect(screen.queryAllByText('Not enough ETH')).toHaveLength(2);
});
});
});
Loading

0 comments on commit a2e54bf

Please sign in to comment.