on df0c310 help sign in
bridge/src/components/L2/Dropdowns/FeeDropdown.tsx
129 lines 3.6 kB history raw
1import React, { useCallback, useEffect, useState } from 'react';
2import { Box, Row, Icon, StatelessTextInput } from '@tlon/indigo-react';
3import { DEFAULT_GAS_PRICE_GWEI } from 'lib/constants';
4import useGasPrice from 'lib/useGasPrice';
6import Dropdown from './Dropdown';
7import './FeeDropdown.scss';
8import { defaultGasValues } from 'lib/getSuggestedGasPrice';
10const PRICE_LABELS = ['Fast', 'Normal', 'Slow'];
12export interface GasPriceData {
13 price: number;
14 wait: string;
15 maxFeePerGas: string; // hex
16 maxPriorityFeePerGas: number;
17 suggestedBaseFeePerGas: number;
20export const formatDisplay = ({ price, wait }: GasPriceData) =>
21 `${price} gwei (${wait} min)`;
23export default function FeeDropdown({
24 setGasPrice,
25}: {
26 setGasPrice: (g: GasPriceData) => void;
27}) {
28 const { suggestedGasPrices }: { suggestedGasPrices: {
29 fast: GasPriceData,
30 average: GasPriceData,
31 low: GasPriceData,
32 }} = useGasPrice(DEFAULT_GAS_PRICE_GWEI);
34 const [open, setOpen] = useState(false);
35 const [useCustom, setUseCustom] = useState(false);
36 const [custom, setCustom] = useState<string | undefined>();
37 const [selected, setSelected] = useState<GasPriceData>(
38 suggestedGasPrices.average
39 );
41 const handleCustom = (e: React.ChangeEvent<HTMLInputElement>) => {
42 const cleanedValue = e.target.value.replace(/[^0-9]/g, '');
43 const cleanedNum = Number(cleanedValue);
44 setCustom(cleanedValue);
45 setGasPrice(defaultGasValues(cleanedNum).average);
47 let customWait = 'Unknown';
49 const { fast, average, low } = suggestedGasPrices;
51 if (cleanedNum < low.price) {
52 customWait = `> ${low.wait}`;
53 } else if (cleanedNum < average.price) {
54 customWait = `~${low.wait}`;
55 } else if (cleanedNum < fast.price) {
56 customWait = `~${average.wait}`;
57 } else {
58 customWait = `< ${fast.wait}`;
59 }
61 setSelected({
62 price: cleanedNum,
63 wait: customWait,
64 maxFeePerGas: cleanedNum,
65 maxPriorityFeePerGas: cleanedNum,
66 suggestedBaseFeePerGas: cleanedNum
67 });
68 };
70 useEffect(() => {
71 setSelected(suggestedGasPrices.average);
72 }, [suggestedGasPrices]);
74 const selectPrice = useCallback(
75 (value: GasPriceData) => () => {
76 setSelected(value);
77 setGasPrice(value);
78 setOpen(false);
79 },
80 [setGasPrice, setSelected, setOpen]
81 );
83 if (useCustom) {
84 return (
85 <Row className="fee-dropdown custom">
86 <StatelessTextInput
87 value={custom}
88 className="custom-input"
89 placeholder="Custom gwei"
90 onChange={handleCustom}
91 autoFocus
92 />
93 <Icon
94 icon="ChevronSouth"
95 onClick={() => {
96 setOpen(true);
97 setUseCustom(false);
98 setCustom('');
99 }}
100 />
101 </Row>
102 );
103 }
105 return (
106 <Dropdown
107 className="fee-dropdown"
108 open={open}
109 value={formatDisplay(selected)}
110 toggleOpen={() => setOpen(!open)}>
111 <Box className="prices">
112 {Object.values(suggestedGasPrices).map(
113 (value: GasPriceData, ind: number) => (
114 <Row
115 className="price"
116 onClick={selectPrice(value)}
117 key={`gas-price-${ind}`}>
118 <Box className="speed">{PRICE_LABELS[ind]}</Box>
119 <Box className="time">{formatDisplay(value)}</Box>
120 </Row>
121 )
122 )}
123 <Row className="price" onClick={() => setUseCustom(true)}>
124 <Box className="time">Custom...</Box>
125 </Row>
126 </Box>
127 </Dropdown>
128 );