Skip to content

Commit f00b685

Browse files
committed
feat: added calculator for rates
1 parent b007146 commit f00b685

File tree

1 file changed

+143
-1
lines changed

1 file changed

+143
-1
lines changed

src/components/infoTooltips/PointsBasedCampaignTooltip.tsx

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import { Box, Typography, useTheme } from '@mui/material';
1+
import { Box, Input, InputAdornment, Typography, useTheme } from '@mui/material';
2+
import { ChangeEvent, useEffect, useState } from 'react';
3+
import { convertAprToApy } from 'src/utils/utils';
24

35
import { FormattedNumber } from '../primitives/FormattedNumber';
46
import { TokenIcon } from '../primitives/TokenIcon';
@@ -22,6 +24,45 @@ export const PointsBasedCampaignTooltip = ({
2224
}: PointBasedCampaignTooltipProps) => {
2325
const theme = useTheme();
2426
const typographyVariant = 'secondary12';
27+
const [inkPriceInput, setInkPriceInput] = useState('');
28+
const [estimatedPointsValue, setEstimatedPointsValue] = useState<number | null>(null);
29+
const [estimatedAPY, setEstimatedAPY] = useState<number | null>(null);
30+
31+
useEffect(() => {
32+
const timeoutId = window.setTimeout(() => {
33+
const trimmedValue = inkPriceInput.trim();
34+
35+
if (!trimmedValue) {
36+
setEstimatedPointsValue(null);
37+
setEstimatedAPY(null);
38+
return;
39+
}
40+
41+
const normalizedValue = trimmedValue.replace(/,/g, '');
42+
const numericPrice = Number(normalizedValue);
43+
44+
if (!Number.isFinite(numericPrice) || numericPrice < 0) {
45+
setEstimatedPointsValue(null);
46+
setEstimatedAPY(null);
47+
return;
48+
}
49+
const dailyUsdValue = pointsPerThousandUsd * numericPrice;
50+
setEstimatedPointsValue(dailyUsdValue);
51+
52+
const aprDecimal = (dailyUsdValue / 1000) * 365;
53+
const apyDecimal = convertAprToApy(aprDecimal);
54+
55+
setEstimatedAPY(apyDecimal * 100);
56+
}, 300);
57+
58+
return () => window.clearTimeout(timeoutId);
59+
}, [inkPriceInput, pointsPerThousandUsd]);
60+
61+
const hasInkPriceInput = inkPriceInput.trim().length > 0;
62+
63+
const handleInkPriceChange = (event: ChangeEvent<HTMLInputElement>) => {
64+
setInkPriceInput(event.target.value);
65+
};
2566

2667
return (
2768
<TextWithTooltip {...rest}>
@@ -93,6 +134,107 @@ export const PointsBasedCampaignTooltip = ({
93134
/>
94135
</Typography>
95136
</Box>
137+
138+
{/* Estimated calculation */}
139+
<Box
140+
sx={{
141+
display: 'flex',
142+
flexDirection: 'column',
143+
gap: 1.25,
144+
p: 1.5,
145+
borderRadius: 1,
146+
border: `1px solid ${theme.palette.divider}`,
147+
backgroundColor: theme.palette.background.paper,
148+
}}
149+
>
150+
<Typography variant={typographyVariant} color={theme.palette.text.secondary}>
151+
Estimate APY and points value
152+
</Typography>
153+
154+
<Input
155+
name="inkPrice"
156+
type="string"
157+
value={inkPriceInput}
158+
onChange={handleInkPriceChange}
159+
placeholder="Introduce an INK price in USD"
160+
disableUnderline
161+
endAdornment={
162+
hasInkPriceInput ? (
163+
<InputAdornment
164+
position="end"
165+
sx={{
166+
color: theme.palette.text.secondary,
167+
pointerEvents: 'none',
168+
pr: 1,
169+
}}
170+
>
171+
USD&nbsp;per&nbsp;INK
172+
</InputAdornment>
173+
) : null
174+
}
175+
sx={{
176+
alignContent: 'center',
177+
borderRadius: 1,
178+
pl: 1,
179+
height: 24,
180+
border: `1px solid ${theme.palette.divider}`,
181+
transition: theme.transitions.create(['border-color', 'box-shadow']),
182+
backgroundColor: theme.palette.background.default,
183+
'&:focus-within': { borderColor: theme.palette.primary.main },
184+
}}
185+
/>
186+
187+
{estimatedPointsValue !== null && (
188+
<>
189+
<Box
190+
sx={{
191+
display: 'flex',
192+
alignItems: 'center',
193+
justifyContent: 'space-between',
194+
px: 1,
195+
py: 1,
196+
borderRadius: 1,
197+
backgroundColor: theme.palette.action.hover,
198+
}}
199+
>
200+
<Typography variant={typographyVariant} color={theme.palette.text.secondary}>
201+
USD value
202+
</Typography>
203+
<Typography variant={typographyVariant} sx={{ fontWeight: 500 }}>
204+
$
205+
<FormattedNumber
206+
value={estimatedPointsValue}
207+
visibleDecimals={2}
208+
variant={typographyVariant}
209+
/>
210+
</Typography>
211+
</Box>
212+
<Box
213+
sx={{
214+
display: 'flex',
215+
alignItems: 'center',
216+
justifyContent: 'space-between',
217+
px: 1,
218+
py: 1,
219+
borderRadius: 1,
220+
backgroundColor: theme.palette.action.hover,
221+
}}
222+
>
223+
<Typography variant={typographyVariant} color={theme.palette.text.secondary}>
224+
APY
225+
</Typography>
226+
<Typography variant={typographyVariant} sx={{ fontWeight: 600 }}>
227+
<FormattedNumber
228+
value={estimatedAPY || 0}
229+
visibleDecimals={2}
230+
variant={typographyVariant}
231+
/>
232+
%
233+
</Typography>
234+
</Box>
235+
</>
236+
)}
237+
</Box>
96238
</Box>
97239
</TextWithTooltip>
98240
);

0 commit comments

Comments
 (0)