Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: balance history tooltip #268

Merged
merged 1 commit into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/api/tokenomics/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export type BalanceSummary = {
total: string;
totalReferrals: string;
totalMiningBlockchain: string;
totalMainnetRewardPoolContribution: string;
};

export type ResurrectRequiredData = {
Expand Down
1 change: 1 addition & 0 deletions src/constants/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const COLORS = {
attention: '#FD4E4E',
attentionDark: '#F53333',
gulfBlue: '#080754',
midnightSapphire: '#061B4B',
madison: '#0D256B',
mariner: '#2D62D9',
periwinkleGray: '#C1CDE1',
Expand Down
15 changes: 11 additions & 4 deletions src/navigation/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,9 @@ import {InviteFriend} from '@screens/InviteFlow/InviteFriend';
import {InviteShare} from '@screens/InviteFlow/InviteShare';
import {QRCodeShare} from '@screens/InviteFlow/QRCodeShare';
import {ActionSheet} from '@screens/Modals/ActionSheet';
import {BalanceHistoryTooltip} from '@screens/Modals/BalanceHistoryTooltip';
import {ContextualMenu} from '@screens/Modals/ContextualMenu';
import {
ContextualMenuButton,
Coordinates,
} from '@screens/Modals/ContextualMenu/types';
import {ContextualMenuButton} from '@screens/Modals/ContextualMenu/types';
import {CountrySelect} from '@screens/Modals/CountrySelect';
import {DateSelect} from '@screens/Modals/DateSelector';
import {JoinTelegramPopUp} from '@screens/Modals/JoinTelegramPopUp';
Expand All @@ -56,6 +54,7 @@ import {ProfilePrivacyEditStep3} from '@screens/Modals/ProfilePrivacyEdit/step3'
import {ReferralCountInfo} from '@screens/Modals/ReferralCountInfo';
import {RepostExample} from '@screens/Modals/RepostExample';
import {Tooltip} from '@screens/Modals/Tooltip';
import {Coordinates} from '@screens/Modals/types';
import {VerifiedTooltipPopUp} from '@screens/Modals/VerifiedTooltipPopUp';
import {News} from '@screens/News';
import {Badges} from '@screens/ProfileFlow/Badges';
Expand Down Expand Up @@ -146,6 +145,9 @@ export type MainStackParamList = {
buttons: ContextualMenuButton[];
onClose?: () => void;
};
BalanceHistoryTooltip: {
coords: Coordinates;
};
ReferralCountInfo: {
hostViewParams: ViewMeasurementsResult;
userId: string;
Expand Down Expand Up @@ -410,6 +412,11 @@ export function MainNavigator() {
component={ContextualMenu}
options={modalOptions}
/>
<MainStack.Screen
name="BalanceHistoryTooltip"
component={BalanceHistoryTooltip}
options={modalOptions}
/>
<MainStack.Screen
name="ReferralCountInfo"
component={ReferralCountInfo}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import {FormattedNumber} from '@components/Labels/FormattedNumber';
import {IceLabel} from '@components/Labels/IceLabel';
import {COLORS} from '@constants/colors';
import {HomeTabStackParamList, MainStackParamList} from '@navigation/Main';
import {useNavigation} from '@react-navigation/native';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import {DataCell} from '@screens/HomeFlow/BalanceHistory/components/PagerHeader/components/DataCell';
import {Coordinates} from '@screens/Modals/types';
import {LogoIcon} from '@svg/LogoIcon';
import {isRTL, t} from '@translations/i18n';
import {font} from '@utils/styles';
Expand All @@ -17,6 +21,15 @@ type Props = {
};

export const BlockchainCell = ({value, currency}: Props) => {
const navigation =
useNavigation<
NativeStackNavigationProp<MainStackParamList & HomeTabStackParamList>
>();
const onInfoPress = (coordinates: Coordinates) => {
navigation.navigate('BalanceHistoryTooltip', {
coords: coordinates,
});
};
return (
<DataCell
icon={
Expand All @@ -43,6 +56,7 @@ export const BlockchainCell = ({value, currency}: Props) => {
<IceLabel reversed={isRTL} iconOffsetY={3.5} color={COLORS.white} />
)
}
onInfoIconPressed={onInfoPress}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: ice License 1.0

import {COLORS} from '@constants/colors';
import {InfoButton} from '@screens/HomeFlow/BalanceHistory/components/PagerHeader/components/InfoButton';
import {Coordinates} from '@screens/Modals/types';
import {isRTL} from '@translations/i18n';
import {font} from '@utils/styles';
import React, {ReactNode} from 'react';
Expand All @@ -12,13 +14,23 @@ type Props = {
label: string;
value: string | ReactNode;
currency?: string | ReactNode;
onInfoIconPressed?: (coordinates: Coordinates) => void;
};

export const DataCell = ({icon, label, value, currency}: Props) => {
export const DataCell = ({
icon,
label,
value,
currency,
onInfoIconPressed,
}: Props) => {
return (
<View style={styles.container}>
<View style={styles.iconWrapper}>{icon}</View>
<Text style={styles.labelText}>{label}</Text>
<Text style={styles.labelText}>
{label}
<InfoButton onInfoIconPressed={onInfoIconPressed} />
</Text>
<View style={styles.value}>
{typeof value === 'string' ? (
<Text style={styles.valueText}>{value}</Text>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: ice License 1.0

import {Touchable} from '@components/Touchable';
import {COLORS} from '@constants/colors';
import {SMALL_BUTTON_HIT_SLOP} from '@constants/styles';
import {Coordinates} from '@screens/Modals/types';
import {InfoOutlineIcon} from '@svg/InfoOutlineIcon';
import {isRTL} from '@translations/i18n';
import React, {useRef} from 'react';
import {StyleSheet, TouchableOpacity} from 'react-native';
import {rem} from 'rn-units';

type Props = {
onInfoIconPressed?: (coordinates: Coordinates) => void;
};

const ICON_SIZE = rem(10);

export function InfoButton({onInfoIconPressed}: Props) {
const buttonRef = useRef<TouchableOpacity>(null);

const onInfoPress = () => {
buttonRef.current?.measure((_, __, width, height, x, y) => {
onInfoIconPressed?.({
top: y + height,
left: x + width / 2,
});
});
};
return onInfoIconPressed ? (
<Touchable
ref={buttonRef}
hitSlop={SMALL_BUTTON_HIT_SLOP}
onPress={onInfoPress}>
<InfoOutlineIcon
style={styles.infoButton}
color={COLORS.shamrock}
width={ICON_SIZE}
height={ICON_SIZE}
/>
</Touchable>
) : null;
}
const styles = StyleSheet.create({
infoButton: {
marginLeft: isRTL ? 0 : rem(4),
marginRight: isRTL ? rem(4) : 0,
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import {rem} from 'rn-units';
// PixelRatio.roundToNearestPixel here is to avoid a small gap between the container and the BottomBump component
export const PAGER_HEADER_HEIGHT = PixelRatio.roundToNearestPixel(rem(116));
export const PAGER_HEADER_BUMP_HEIGHT = rem(8);
export const PAGER_HEADER_OUTER_HEIGHT =
PAGER_HEADER_HEIGHT + PAGER_HEADER_BUMP_HEIGHT;

export const PagerHeader = () => {
const [activeIndex, setActiveIndex] = useState(0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// SPDX-License-Identifier: ice License 1.0

import {COLORS} from '@constants/colors';
import {commonStyles, windowHeight, windowWidth} from '@constants/styles';
import {Coordinates} from '@screens/Modals/types';
import {balanceSummarySelector} from '@store/modules/Tokenomics/selectors';
import {RoundedTriangle} from '@svg/RoundedTriangle';
import {isRTL, t} from '@translations/i18n';
import {formatNumberString, parseNumber} from '@utils/numbers';
import {font} from '@utils/styles';
import React, {memo, useRef} from 'react';
import {StyleSheet, Text, View, ViewStyle} from 'react-native';
import {LayoutChangeEvent} from 'react-native/Libraries/Types/CoreEventTypes';
import {useSelector} from 'react-redux';
import {rem} from 'rn-units';

type Props = {
coordinates: Coordinates;
};

export const ROUNDED_TRIANGLE_SIZE = rem(20);

function getRight(coordinates: Coordinates) {
return (
coordinates.right ?? (coordinates.left ? windowWidth - coordinates.left : 0)
);
}
function getTop(coordinates: Coordinates) {
return (
coordinates.top ??
(coordinates.bottom ? windowHeight - coordinates.bottom : 0)
);
}

const CELLS_NUMBER = 2;

export const Tooltip = memo(({coordinates}: Props) => {
const balanceSummary = useSelector(balanceSummarySelector);
const right = getRight(coordinates);

const maxWidthRef = useRef(0);
const numberCellsToRenderRef = useRef(CELLS_NUMBER);
const [cellDynamicStyle, setCellDynamicStyle] =
React.useState<ViewStyle | null>(null);
const onCellLayout = ({nativeEvent}: LayoutChangeEvent) => {
maxWidthRef.current = Math.max(
maxWidthRef.current,
nativeEvent.layout.width,
);
numberCellsToRenderRef.current -= 1;
if (!numberCellsToRenderRef.current) {
setCellDynamicStyle({
width: maxWidthRef.current,
});
}
};
return (
<View
style={[
styles.mainContainer,
commonStyles.shadow,
{
top: getTop(coordinates) + ROUNDED_TRIANGLE_SIZE,
right: isRTL ? (windowWidth - right) / 2 : right / 2,
},
]}>
<RoundedTriangle
fill={COLORS.gulfBlue}
width={ROUNDED_TRIANGLE_SIZE}
height={ROUNDED_TRIANGLE_SIZE}
style={[
styles.arrow,
{
right: isRTL
? (windowWidth - right) / 2 - ROUNDED_TRIANGLE_SIZE / 2 - rem(3)
: right / 2 - ROUNDED_TRIANGLE_SIZE / 2 - rem(2),
},
]}
/>
<View style={[styles.cell, cellDynamicStyle]} onLayout={onCellLayout}>
<Text style={styles.labelText}>{t('balance_history.you')}</Text>
<Text style={styles.valueText}>
{balanceSummary &&
formatNumberString(
String(
parseNumber(balanceSummary.totalMiningBlockchain) -
parseNumber(
balanceSummary.totalMainnetRewardPoolContribution,
),
),
{minimumFractionDigits: 0, maximumFractionDigits: 0},
)}
</Text>
</View>
<View style={styles.cellSeparator} />
<View style={[styles.cell, cellDynamicStyle]} onLayout={onCellLayout}>
<Text style={styles.labelText}>
{t('balance_history.contribution')}
</Text>
<Text style={styles.valueText}>
{balanceSummary &&
formatNumberString(
balanceSummary.totalMainnetRewardPoolContribution,
{minimumFractionDigits: 0, maximumFractionDigits: 0},
)}
</Text>
</View>
</View>
);
});

const styles = StyleSheet.create({
mainContainer: {
backgroundColor: COLORS.midnightSapphire,
position: 'absolute',
borderRadius: rem(12),
flexDirection: 'row',
alignItems: 'center',
},
cell: {
minWidth: rem(100),
padding: rem(10),
alignItems: 'center',
},
cellSeparator: {
width: 1,
backgroundColor: COLORS.periwinkleGray,
height: '80%',
},
labelText: {
...font(10, 14, 'regular', 'white', 'center'),
textTransform: 'uppercase',
opacity: 0.7,
},
valueText: {
...font(14, 20, 'bold'),
},
arrow: {
position: 'absolute',
top: -ROUNDED_TRIANGLE_SIZE + rem(4),
},
});
29 changes: 29 additions & 0 deletions src/screens/Modals/BalanceHistoryTooltip/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: ice License 1.0

import {commonStyles} from '@constants/styles';
import {HomeTabStackParamList, MainStackParamList} from '@navigation/Main';
import {RouteProp, useNavigation, useRoute} from '@react-navigation/native';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import {Tooltip} from '@screens/Modals/BalanceHistoryTooltip/components/Tooltip';
import React, {memo} from 'react';
import {TouchableWithoutFeedback, View} from 'react-native';

export const BalanceHistoryTooltip = memo(() => {
const navigation =
useNavigation<NativeStackNavigationProp<HomeTabStackParamList>>();
const {
params: {coords},
} = useRoute<RouteProp<MainStackParamList, 'BalanceHistoryTooltip'>>();

const closeMenu = () => {
navigation.goBack();
};

return (
<TouchableWithoutFeedback onPress={closeMenu}>
<View style={commonStyles.flexOne}>
<Tooltip coordinates={coords} />
</View>
</TouchableWithoutFeedback>
);
});
6 changes: 2 additions & 4 deletions src/screens/Modals/ContextualMenu/components/Menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
import {Touchable} from '@components/Touchable';
import {COLORS} from '@constants/colors';
import {commonStyles} from '@constants/styles';
import {
ContextualMenuButton,
Coordinates,
} from '@screens/Modals/ContextualMenu/types';
import {ContextualMenuButton} from '@screens/Modals/ContextualMenu/types';
import {Coordinates} from '@screens/Modals/types';
import {RoundedTriangle} from '@svg/RoundedTriangle';
import {font} from '@utils/styles';
import React, {memo} from 'react';
Expand Down
7 changes: 0 additions & 7 deletions src/screens/Modals/ContextualMenu/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,3 @@ export type ContextualMenuButton = {
onPress: () => void;
id?: 'help' | 'staking' | 'notifications' | 'stats' | 'tips';
};

export type Coordinates = {
top?: number;
right?: number;
bottom?: number;
left?: number;
};
8 changes: 8 additions & 0 deletions src/screens/Modals/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: ice License 1.0

export type Coordinates = {
top?: number;
right?: number;
bottom?: number;
left?: number;
};
Loading
Loading