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
35import { FormattedNumber } from '../primitives/FormattedNumber' ;
46import { 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 per 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