Skip to content

Commit

Permalink
feat: balance history tooltip (#268)
Browse files Browse the repository at this point in the history
  • Loading branch information
ice-hades authored Feb 6, 2024
1 parent ec681fe commit 2725631
Show file tree
Hide file tree
Showing 57 changed files with 405 additions and 63 deletions.
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
142 changes: 142 additions & 0 deletions src/screens/Modals/BalanceHistoryTooltip/components/Tooltip/index.tsx
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

0 comments on commit 2725631

Please sign in to comment.