Skip to content

Commit

Permalink
feat: updated pooled-staking learn more modal with generic interactiv…
Browse files Browse the repository at this point in the history
…e timespan chart component
  • Loading branch information
Matt561 committed Dec 19, 2024
1 parent fecf163 commit f7b65ad
Show file tree
Hide file tree
Showing 26 changed files with 705 additions and 841 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface ChartNavigationButtonProps {
label: string;
selected: boolean;
}

const ChartNavigationButton = ({
onPress,
label,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const styleSheet = (params: {
marginTop: 24,
paddingBottom: 16,
paddingHorizontal: 16,
flexWrap: 'wrap',
},
chartTimespanButton: {
flexDirection: 'column',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,12 @@ interface DataGradientProps {
const getGradientOpacityByDataSetSize = (dataSetSize: number) => {
let opacityTop, opacityBottom;

if (dataSetSize <= 10) {
if (dataSetSize <= 30) {
opacityTop = 0.2;
opacityBottom = 0;
}

if (dataSetSize >= 30) {
opacityTop = 0.35;
opacityBottom = 0;
}

if (dataSetSize >= 60) {
opacityBottom = 0.2;
} else {
opacityTop = 0.4;
opacityBottom = 0;
}

if (dataSetSize >= 100) {
opacityTop = 0.7;
opacityBottom = 0.25;
opacityBottom = 0.2;
}

return { opacityTop, opacityBottom };
Expand All @@ -48,7 +36,7 @@ const DataGradient = ({ dataPoints, color }: DataGradientProps) => {
return (
<Defs key="dataGradient">
<LinearGradient id="dataGradient" x1={0} y1={0} x2={0} y2={'100%'}>
<Stop stopColor={defaultColor} stopOpacity={opacityTop} />
<Stop stopColor={color ?? defaultColor} stopOpacity={opacityTop} />
<Stop
offset={1}
stopColor={colors.background.default}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,25 @@ import React from 'react';
import { G, Circle, Line } from 'react-native-svg';
import { useTheme } from '../../../../../../../util/theme';

interface TooltipProps {
dailyAprs: number[];
interface GraphCursorProps {
data: number[];
currentX: number;
lineColor?: string;
circleColor?: string;
color?: string;
// Props below are passed in implicitly by <AreaChart/> from react-native-svg-charts
// src: https://github.com/JesperLekland/react-native-svg-charts
x?: (index: number) => number;
y?: (value: number) => number;
ticks?: number[];
}

const Tooltip = ({
dailyAprs,
currentX,
x,
y,
lineColor,
circleColor,
}: TooltipProps) => {
const GraphCursor = ({ data, currentX, x, y, color }: GraphCursorProps) => {
const { colors } = useTheme();

const defaultColor = colors.success.default;

if ((currentX && currentX < 0) || !dailyAprs) return null;
if ((currentX && currentX < 0) || !data) return null;

const selectedDailyApr = dailyAprs[currentX];
const selectedDailyApr = data[currentX];

// Prevents <Circle/> crash when attempting to parse small floating point numbers (e.g. 0.0123)
if (!selectedDailyApr) return null;
Expand All @@ -39,19 +31,19 @@ const Tooltip = ({
<Line
y1={1}
y2={'100%'}
stroke={lineColor ?? defaultColor}
stroke={color ?? defaultColor}
strokeWidth={1}
/>
<Circle
cy={y?.(selectedDailyApr)}
r={5}
stroke={circleColor ?? defaultColor}
stroke={color ?? defaultColor}
strokeWidth={1}
fill={circleColor ?? defaultColor}
fill={color ?? defaultColor}
/>
</G>
</G>
);
};

export default Tooltip;
export default GraphCursor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { StyleSheet } from 'react-native';

const styleSheet = () =>
StyleSheet.create({
container: {
paddingVertical: 16,
gap: 4,
alignItems: 'center',
},
});

export default styleSheet;
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import { View } from 'react-native';
import Text, {
TextVariant,
TextColor,
} from '../../../../../../../component-library/components/Texts/Text';
import { useStyles } from '../../../../../../hooks/useStyles';
import styleSheet from './GraphTooltip.styles';

interface GraphTooltipProps {
title: string;
subtitle: string;
color?: string;
}

const GraphTooltip = ({ title, subtitle, color }: GraphTooltipProps) => {
const { styles } = useStyles(styleSheet, {});

return (
<View style={styles.container}>
<Text variant={TextVariant.HeadingLG} color={color ?? TextColor.Success}>
{title}
</Text>
<Text variant={TextVariant.BodyMDMedium} color={TextColor.Alternative}>
{subtitle}
</Text>
</View>
);
};

export default GraphTooltip;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { colors } from '@metamask/design-tokens';
import { CHART_BUTTONS } from './InteractiveTimespanChart';
import { GraphOptions } from './InteractiveTimespanChart.types';

const DEFAULT_INSET = 0;

export const DEFAULT_GRAPH_OPTIONS: GraphOptions = {
insetTop: DEFAULT_INSET,
insetRight: DEFAULT_INSET,
insetBottom: DEFAULT_INSET,
insetLeft: DEFAULT_INSET,
timespanButtons: CHART_BUTTONS,
color: colors.light.success.default,
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,10 @@ import { StyleSheet } from 'react-native';
const styleSheet = () =>
StyleSheet.create({
chartContainer: {
flexDirection: 'column',
justifyContent: 'flex-start',
paddingVertical: 16,
},
chart: {
height: 112,
// paddingHorizontal: 8,
},
earningRate: {
paddingVertical: 16,
gap: 4,
alignItems: 'center',
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { strings } from '../../../../../../../locales/i18n';
import { ChartButton } from './ChartTimespanButtonGroup/ChartTimespanButtonGroup.types';

// Small dataset ~10 points or less
export const SMALL_DATASET_THRESHOLD = 10;
export const SMALL_DATASET_PADDING = 16;
// Large dataset ~90 points and more
export const SMALL_DATASET_SNAP_RATIO = 0.5;

export const CHART_BUTTONS: ChartButton[] = [
{ label: strings('stake.interactive_chart.timespan_buttons.7D'), value: 7 },
{ label: strings('stake.interactive_chart.timespan_buttons.1M'), value: 30 },
{ label: strings('stake.interactive_chart.timespan_buttons.3M'), value: 90 },
{ label: strings('stake.interactive_chart.timespan_buttons.6M'), value: 180 },
];

export enum CHART_TIMESPAN_VALUES {
ONE_WEEK = 7,
ONE_MONTH = 30,
THREE_MONTHS = 90,
SIX_MONTHS = 180,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ChartButton } from './ChartTimespanButtonGroup/ChartTimespanButtonGroup.types';

export type DataPoint = Record<string, unknown>;

export type Accessor<T, R> = (point: T) => R;

export interface GraphOptions {
insetTop: number;
insetBottom: number;
insetLeft: number;
insetRight: number;
timespanButtons: ChartButton[];
color: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { VaultAprs } from '@metamask/stake-sdk';
import BigNumber from 'bignumber.js';
import { strings } from '../../../../../../../locales/i18n';

export const calculateSegmentCenters = (
dataPoints: number[] | string[],
segmentWidth: number,
) =>
dataPoints.map((_, index) => {
/**
* Ex. If each segment is 30px wide:
* The start position of first segment (index: 0) = 0 * segmentWidth OR 0 * 30px = 0
* The center position of the first segment (index: 0) = startPosition + segmentWidth / 2 OR 0 + 30 / 2 = 15
*/
const startOfSegment = index * segmentWidth;
const centerOfSegment = startOfSegment + segmentWidth / 2;
return centerOfSegment;
});

export const formatChartDate = (timestamp: string) =>
new Date(timestamp).toUTCString().split(' ').slice(0, 4).join(' ');

// Example: Sun, 01 Dec 2024
export const formatDailyAprReward = (reward: {
daily_apy: string;
timestamp: string;
}) => ({
apr: `${new BigNumber(reward.daily_apy).toFixed(2, BigNumber.ROUND_DOWN)}%`,
timestamp: new Date(reward.timestamp)
.toUTCString()
.split(' ')
.slice(0, 4)
.join(' '),
});

export const getGraphContentInset = (dataPoints: number[]) => {
let inset = 0;

if (dataPoints.length <= 10) inset = 20;

if (dataPoints.length >= 30) inset = 15;

if (dataPoints.length >= 90) inset = 10;

if (dataPoints.length >= 180) inset = 5;

return inset;
};

export const parseVaultTimespanAprsResponse = (
vaultTimespanAprs: VaultAprs,
) => {
const numDaysMap: Record<
keyof VaultAprs,
{ numDays: number; label: string }
> = {
oneDay: { numDays: 1, label: strings('stake.today') },
oneWeek: { numDays: 7, label: strings('stake.one_week_average') },
oneMonth: { numDays: 30, label: strings('stake.one_month_average') },
threeMonths: { numDays: 90, label: strings('stake.three_month_average') },
sixMonths: { numDays: 180, label: strings('stake.six_month_average') },
oneYear: { numDays: 365, label: strings('stake.one_year_average') },
};

return Object.entries(vaultTimespanAprs).reduce<
Record<number, { apr: string; numDays: number; label: string }>
>((map, [key, value]) => {
const numDaysMapEntry = numDaysMap[key as keyof typeof numDaysMap];
map[numDaysMapEntry.numDays] = { apr: value, ...numDaysMapEntry };
return map;
}, {});
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const PlotLine = ({ line, doesChartHaveData, color }: Partial<LineProps>) => {
key="line"
d={line}
stroke={doesChartHaveData ? lineColor : themeColors.text.alternative}
strokeWidth={1.5}
strokeWidth={1.75}
fill="none"
opacity={doesChartHaveData ? 1 : 0.85}
/>
Expand Down
Loading

0 comments on commit f7b65ad

Please sign in to comment.