Skip to content

Commit 024a9a3

Browse files
authored
Merge pull request #30 from Maphikza/feat-ui/unconfirmed-transactions
Updating relay settings type and supporting code for file storage
2 parents 50a3bde + b0103af commit 024a9a3

8 files changed

Lines changed: 145 additions & 379 deletions

File tree

.env.development

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
REACT_APP_BASE_URL=http://localhost:9002
2-
# REACT_APP_BASE_URL=https://11561ba2d27f.ngrok.app
2+
REACT_APP_WALLET_BASE_URL=http://localhost:9003 # New wallet base URL
33
REACT_APP_ASSETS_BUCKET=http://localhost
44
REACT_APP_DEMO_MODE=false
55

6-
# more info https://create-react-app.dev/docs/advanced-configuration
6+
# More info https://create-react-app.dev/docs/advanced-configuration
77
ESLINT_NO_DEV_ERRORS=true
88
TSC_COMPILE_ON_ERROR=true

src/components/nft-dashboard/Balance/components/SendForm/SendForm.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const SendForm: React.FC<SendFormProps> = ({ onSend }) => {
5353

5454
// Debounced effect to calculate transaction size when the amount changes, with JWT
5555
useEffect(() => {
56-
56+
5757
const debounceTimeout = setTimeout(() => {
5858
const fetchTransactionSize = async () => {
5959
if (isValidAddress(formData.address) && isDetailsOpen) {
@@ -65,7 +65,7 @@ const SendForm: React.FC<SendFormProps> = ({ onSend }) => {
6565
await login(); // Perform login if not authenticated
6666
}
6767

68-
const response = await fetch('http://localhost:9003/calculate-tx-size', {
68+
const response = await fetch(`${config.walletBaseURL}/calculate-tx-size`, {
6969
method: 'POST',
7070
headers: {
7171
'Content-Type': 'application/json',
@@ -185,9 +185,9 @@ const SendForm: React.FC<SendFormProps> = ({ onSend }) => {
185185
await login(); // Perform login if not authenticated
186186
}
187187

188-
188+
189189
// Step 2: Initiate the new transaction with the JWT token
190-
const response = await fetch('http://localhost:9003/transaction', {
190+
const response = await fetch(`${config.walletBaseURL}/transaction`, {
191191
method: 'POST',
192192
headers: {
193193
'Content-Type': 'application/json',
@@ -301,7 +301,13 @@ const SendForm: React.FC<SendFormProps> = ({ onSend }) => {
301301
/>
302302
RBF Opt In
303303
</S.RBFWrapper>
304-
<TieredFees inValidAmount={inValidAmount} handleFeeChange={handleFeeRateChange} txSize={txSize} />
304+
<TieredFees
305+
invalidAmount={inValidAmount} // Note: 'invalidAmount' property is now camelCase to match prop names
306+
handleFeeChange={handleFeeRateChange}
307+
transactionSize={txSize} // Pass the transaction size value
308+
originalFeeRate={0} // Pass 0 or appropriate value for new transactions
309+
/>
310+
305311
</S.TiersContainer>
306312
<BaseRow justify={'center'}>
307313
<S.SendFormButton
Lines changed: 74 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
import React, { useEffect, useState } from 'react';
2-
import * as S from './TieredFees.styles';
3-
import { useResponsive } from '@app/hooks/useResponsive';
4-
import { tiers } from '../../SendForm';
5-
import { set } from 'date-fns';
1+
import React, { useState, useEffect } from "react";
2+
import * as S from "./TieredFees.styles";
3+
import { useResponsive } from "@app/hooks/useResponsive";
64

75
interface FeeRecommendation {
86
fastestFee: number;
@@ -11,107 +9,140 @@ interface FeeRecommendation {
119
economyFee: number;
1210
minimumFee: number;
1311
}
14-
type Fees = {
15-
[key in tiers]: number;
16-
};
12+
13+
type Tier = "low" | "med" | "high";
14+
15+
interface Fees {
16+
low: number;
17+
med: number;
18+
high: number;
19+
}
20+
21+
22+
// interface Fees {
23+
// [key in Tier]: number;
24+
// }
25+
1726
interface TieredFeesProps {
1827
handleFeeChange: (fee: number) => void;
19-
inValidAmount: boolean;
20-
txSize: number | null; // Transaction size passed down from SendForm
28+
invalidAmount: boolean;
29+
transactionSize: number | null; // Transaction size passed down from parent
30+
originalFeeRate?: number; // Optional original fee rate (used for replacements)
2131
}
2232

23-
const TieredFees: React.FC<TieredFeesProps> = ({ inValidAmount, handleFeeChange, txSize }) => {
33+
const DEFAULT_FEES: Fees = { low: 3, med: 4, high: 5 };
34+
35+
const TieredFees: React.FC<TieredFeesProps> = ({
36+
handleFeeChange,
37+
invalidAmount,
38+
transactionSize,
39+
originalFeeRate = 0,
40+
}) => {
2441
const { isDesktop, isTablet } = useResponsive();
42+
const [selectedTier, setSelectedTier] = useState<Tier>("low");
43+
const [fees, setFees] = useState<Fees>(DEFAULT_FEES);
44+
const [estimatedFee, setEstimatedFee] = useState<Fees>({ low: 0, med: 0, high: 0 });
2545
const [loadingRecommendation, setLoadingRecommendation] = useState(false);
26-
const [fetchedrecommendation, setFetchedRecommendation] = useState(false);
27-
const [fees, setFees] = useState<Fees>({ low: 0, med: 0, high: 0 });
28-
const [selectedTier, setSelectedTier] = useState<tiers | null>('low');
29-
const [estimatedFee, setEstimatedFee] = useState({ low: 0, med: 0, high: 0 });
46+
const [fetchedRecommendation, setFetchedRecommendation] = useState(false);
47+
48+
// Adjust fees for replacement transactions if originalFeeRate > 0
49+
const adjustFees = (fetchedFees: Fees) => {
50+
if (originalFeeRate > 0) {
51+
const adjustedFees = { ...fetchedFees };
52+
adjustedFees.low = Math.max(originalFeeRate + 1, fetchedFees.low);
53+
adjustedFees.med = Math.max(adjustedFees.low + 1, fetchedFees.med);
54+
adjustedFees.high = Math.max(adjustedFees.med + 1, fetchedFees.high);
55+
return adjustedFees;
56+
}
57+
return fetchedFees;
58+
};
3059

3160
useEffect(() => {
32-
if (loadingRecommendation || fetchedrecommendation) return;
61+
if (loadingRecommendation || fetchedRecommendation) return;
3362
const fetchFees = async () => {
3463
setLoadingRecommendation(true);
3564
try {
36-
const response = await fetch('https://mempool.space/api/v1/fees/recommended');
65+
const response = await fetch("https://mempool.space/api/v1/fees/recommended");
3766
const data: FeeRecommendation = await response.json();
38-
setFees({
67+
const fetchedFees: Fees = {
3968
low: data.economyFee,
4069
med: data.halfHourFee,
4170
high: data.fastestFee,
42-
});
71+
};
72+
const adjustedFees = adjustFees(fetchedFees);
73+
setFees(adjustedFees);
4374
setFetchedRecommendation(true);
4475
} catch (error) {
45-
console.error('Failed to fetch fees:', error);
76+
console.error("Failed to fetch fees:", error);
77+
setFees(adjustFees(DEFAULT_FEES));
4678
}
4779
setLoadingRecommendation(false);
4880
};
49-
5081
fetchFees();
51-
}, []);
82+
}, [originalFeeRate]);
5283

5384
// Update estimated fees whenever the fees or transaction size change
5485
useEffect(() => {
55-
if (txSize) {
86+
if (transactionSize) {
5687
setEstimatedFee({
57-
low: txSize * fees.low,
58-
med: txSize * fees.med,
59-
high: txSize * fees.high,
88+
low: Math.ceil(transactionSize * fees.low),
89+
med: Math.ceil(transactionSize * fees.med),
90+
high: Math.ceil(transactionSize * fees.high),
6091
});
6192
}
62-
}, [fees, txSize]);
93+
}, [fees, transactionSize]);
6394

64-
const handleTierChange = (tier: any) => {
65-
setSelectedTier(tier.id);
95+
const handleTierChange = (tier: Tier) => {
96+
setSelectedTier(tier);
6697
};
6798

6899
useEffect(() => {
69-
handleFeeChange(fees[selectedTier as tiers]);
70-
}, [selectedTier, fees]);
100+
handleFeeChange(fees[selectedTier]);
101+
}, [selectedTier, fees, handleFeeChange]);
71102

72103
return (
73104
<S.TiersWrapper $isMobile={!isDesktop && !isTablet}>
74105
<S.TierCard
75106
$isMobile={!isDesktop}
76-
onClick={() => handleTierChange({ id: 'low' })}
77-
className={`tier-hover ${selectedTier === 'low' ? 'selected' : ''} ${
78-
selectedTier === 'low' && inValidAmount ? 'invalidAmount' : ''
107+
onClick={() => handleTierChange("low")}
108+
className={`tier-hover ${selectedTier === "low" ? "selected" : ""} ${
109+
selectedTier === "low" && invalidAmount ? "invalidAmount" : ""
79110
} `}
80111
>
81112
<S.TierCardContent>
82113
{`Low`}
83114
<br />
84115
{`Priority`}
85116
<S.RateValueWrapper>
86-
{`${fees.low}`} <br /> {`sat/vB`}
117+
{`${fees.low}`} <br /> {`sat/vB`}
87118
<S.RateValue>{`${estimatedFee.low} Sats`}</S.RateValue> {/* Show estimated fee */}
88119
</S.RateValueWrapper>
89120
</S.TierCardContent>
90121
</S.TierCard>
91122

92123
<S.TierCard
93124
$isMobile={!isDesktop}
94-
onClick={() => handleTierChange({ id: 'med' })}
95-
className={`tier-hover ${selectedTier === 'med' ? 'selected' : ''} ${
96-
selectedTier === 'med' && inValidAmount ? 'invalidAmount' : ''
125+
onClick={() => handleTierChange("med")}
126+
className={`tier-hover ${selectedTier === "med" ? "selected" : ""} ${
127+
selectedTier === "med" && invalidAmount ? "invalidAmount" : ""
97128
} `}
98129
>
99130
<S.TierCardContent>
100131
{`Medium`}
101132
<br />
102133
{`Priority`}
103134
<S.RateValueWrapper>
104-
{`${fees.med}`} <br /> {`sat/vB`}
135+
{`${fees.med}`} <br /> {`sat/vB`}
105136
<S.RateValue>{`${estimatedFee.med} Sats`}</S.RateValue> {/* Show estimated fee */}
106137
</S.RateValueWrapper>
107138
</S.TierCardContent>
108139
</S.TierCard>
109140

110141
<S.TierCard
111142
$isMobile={!isDesktop}
112-
onClick={() => handleTierChange({ id: 'high' })}
113-
className={`tier-hover ${selectedTier === 'high' ? 'selected' : ''} ${
114-
selectedTier === 'high' && inValidAmount ? 'invalidAmount' : ''
143+
onClick={() => handleTierChange("high")}
144+
className={`tier-hover ${selectedTier === "high" ? "selected" : ""} ${
145+
selectedTier === "high" && invalidAmount ? "invalidAmount" : ""
115146
} `}
116147
>
117148
<S.TierCardContent>
@@ -130,119 +161,4 @@ const TieredFees: React.FC<TieredFeesProps> = ({ inValidAmount, handleFeeChange,
130161
);
131162
};
132163

133-
export default TieredFees;
134-
135-
// import React, { useEffect, useState } from 'react';
136-
// import * as S from './TieredFees.styles';
137-
// import { useResponsive } from '@app/hooks/useResponsive';
138-
// import { tiers } from '../../SendForm';
139-
140-
// interface FeeRecommendation {
141-
// fastestFee: number;
142-
// halfHourFee: number;
143-
// hourFee: number;
144-
// economyFee: number;
145-
// minimumFee: number;
146-
// }
147-
// type Fees = {
148-
// [key in tiers]: number;
149-
// };
150-
// interface TieredFeesProps {
151-
// // Define the props for your component here
152-
// handleFeeChange: (fee: number) => void;
153-
// inValidAmount: boolean;
154-
// }
155-
156-
// const TieredFees: React.FC<TieredFeesProps> = ({ inValidAmount, handleFeeChange }) => {
157-
// const { isDesktop, isTablet } = useResponsive();
158-
// const [fees, setFees] = useState<Fees>({ low: 0, med: 0, high: 0 });
159-
// const [selectedTier, setSelectedTier] = useState<tiers | null>('low');
160-
161-
// useEffect(() => {
162-
// const fetchFees = async () => {
163-
// try {
164-
// const response = await fetch('https://mempool.space/api/v1/fees/recommended');
165-
// const data: FeeRecommendation = await response.json();
166-
// setFees({
167-
// low: data.economyFee,
168-
// med: data.halfHourFee,
169-
// high: data.fastestFee,
170-
// });
171-
// } catch (error) {
172-
// console.error('Failed to fetch fees:', error);
173-
// }
174-
// };
175-
176-
// fetchFees();
177-
// }, []);
178-
// const handleTierChange = (tier: any) => {
179-
// console.log(tier);
180-
// setSelectedTier(tier.id);
181-
// };
182-
183-
// useEffect(() => {
184-
// handleFeeChange(fees[selectedTier as tiers]);
185-
// }, [selectedTier]);
186-
// return (
187-
// <S.TiersWrapper $isMobile={!isDesktop || !isTablet }>
188-
// <S.TierCard
189-
// $isMobile={!isDesktop}
190-
// onClick={() => handleTierChange({ id: 'low', rate: fees.med })}
191-
// className={`tier-hover ${selectedTier === 'low' ? 'selected' : ''} ${
192-
// selectedTier === 'low' && inValidAmount ? 'invalidAmount' : ''
193-
// } `}
194-
// >
195-
// <S.TierCardContent>
196-
// {`Low`}
197-
// <br />
198-
// {`Priority`}
199-
// <S.RateValueWrapper>
200-
// <span>{`${fees.low} sat/vB`}</span>
201-
// <S.RateValue>{`${fees.low} Sats`}</S.RateValue>
202-
// </S.RateValueWrapper>
203-
// </S.TierCardContent>
204-
// </S.TierCard>
205-
206-
// <S.TierCard
207-
// $isMobile={!isDesktop}
208-
// onClick={() => handleTierChange({ id: 'med', rate: fees.med })}
209-
// className={`tier-hover ${selectedTier === 'med' ? 'selected' : ''} ${
210-
// selectedTier === 'med' && inValidAmount ? 'invalidAmount' : ''
211-
// } `}
212-
// >
213-
// <S.TierCardContent>
214-
// {`Medium`}
215-
// <br />
216-
// {`Priority`}
217-
// <S.RateValueWrapper>
218-
// <span>{`${fees.med} sat/vB`}</span>
219-
// <S.RateValue>{`${fees.med} Sats`}</S.RateValue>
220-
// </S.RateValueWrapper>
221-
// </S.TierCardContent>
222-
// </S.TierCard>
223-
224-
// <S.TierCard
225-
// $isMobile={!isDesktop}
226-
// onClick={() => handleTierChange({ id: 'high', rate: fees.high })}
227-
// className={`tier-hover ${selectedTier === 'high' ? 'selected' : ''} ${
228-
// selectedTier === 'high' && inValidAmount ? 'invalidAmount' : ''
229-
// } `}
230-
// >
231-
// <S.TierCardContent>
232-
// <S.TierCardAmount>
233-
// {' '}
234-
// {`High`}
235-
// <br />
236-
// {`Priority`}
237-
// </S.TierCardAmount>
238-
// <S.RateValueWrapper>
239-
// <span>{`${fees.high} sat/vB`}</span>
240-
// <S.RateValue>{`${fees.high} Sats`}</S.RateValue>
241-
// </S.RateValueWrapper>
242-
// </S.TierCardContent>
243-
// </S.TierCard>
244-
// </S.TiersWrapper>
245-
// );
246-
// };
247-
248-
// export default TieredFees;
164+
export default TieredFees;

0 commit comments

Comments
 (0)