Skip to content

Commit c38cbd4

Browse files
add success state
1 parent ed7cfb9 commit c38cbd4

File tree

5 files changed

+95
-27
lines changed

5 files changed

+95
-27
lines changed

src/internal/svg/checkmarkSvg.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export const checkmarkSvg = (
22
<svg
3-
width="25"
4-
height="24"
3+
width="16"
4+
height="16"
55
viewBox="0 0 25 24"
66
fill="none"
77
xmlns="http://www.w3.org/2000/svg"

src/swap/components/FundSwapButton.tsx

+36-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback } from 'react';
1+
import { useCallback, useMemo } from 'react';
22
import { Spinner } from '../../internal/components/Spinner';
33
import {
44
cn,
@@ -9,24 +9,51 @@ import {
99
pressable,
1010
} from '../../styles/theme';
1111
import { useFundSwapContext } from './FundSwapProvider';
12+
import { checkmarkSvg } from '../../internal/svg/checkmarkSvg';
1213

1314
export function FundSwapButton() {
14-
const { setIsDropdownOpen } = useFundSwapContext();
15-
const isLoading = false;
16-
const isDisabled = false;
15+
const {
16+
setIsDropdownOpen,
17+
fromETH,
18+
fromUSDC,
19+
to,
20+
lifecycleStatus: { statusName },
21+
} = useFundSwapContext();
22+
const isLoading =
23+
to?.loading ||
24+
fromETH.loading ||
25+
fromUSDC.loading ||
26+
statusName === 'transactionPending' ||
27+
statusName === 'transactionApproved';
28+
29+
const isDisabled =
30+
!fromETH.amount ||
31+
!fromUSDC.amount ||
32+
!fromETH.token ||
33+
!fromUSDC.token ||
34+
!to?.amount ||
35+
!to?.token ||
36+
isLoading;
1737

1838
const handleSubmit = useCallback(() => {
1939
setIsDropdownOpen(true);
2040
}, [setIsDropdownOpen]);
2141

42+
const buttonContent = useMemo(() => {
43+
if (statusName === 'success') {
44+
return checkmarkSvg;
45+
}
46+
return 'Buy';
47+
}, [statusName]);
48+
2249
return (
2350
<button
2451
type="button"
2552
className={cn(
2653
background.primary,
2754
border.radius,
28-
'rounded-xl',
29-
'px-4 py-3',
55+
'flex rounded-xl',
56+
'px-4 py-3 h-12 w-24 items-center justify-center',
3057
isDisabled && pressable.disabled,
3158
text.headline,
3259
)}
@@ -36,7 +63,9 @@ export function FundSwapButton() {
3663
{isLoading ? (
3764
<Spinner />
3865
) : (
39-
<span className={cn(text.headline, color.inverse)}>Buy</span>
66+
<span className={cn(text.headline, color.foreground)}>
67+
{buttonContent}
68+
</span>
4069
)}
4170
</button>
4271
);

src/swap/components/FundSwapDropdown.tsx

+15-8
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
import { TokenImage } from '../../token';
2-
import { background, cn, color } from '../../styles/theme';
2+
import { background, cn, color, pressable } from '../../styles/theme';
33
import { useFundSwapContext } from './FundSwapProvider';
44
import type { SwapUnit } from '../types';
55
import { useCallback } from 'react';
66

77
function TokenItem({ swapUnit }: { swapUnit: SwapUnit }) {
8-
const { handleSubmit } = useFundSwapContext();
8+
const { handleSubmit, setIsDropdownOpen } = useFundSwapContext();
99

1010
if (!swapUnit?.token) {
1111
return null;
1212
}
1313

1414
const handleClick = useCallback(() => {
15+
setIsDropdownOpen(false);
1516
handleSubmit(swapUnit);
16-
}, [handleSubmit, swapUnit]);
17+
}, [handleSubmit, swapUnit, setIsDropdownOpen]);
1718

1819
return (
19-
<div className="flex items-center gap-2" onClick={handleClick}>
20+
<button
21+
className={cn(
22+
'flex items-center gap-2 rounded-lg p-2',
23+
'hover:bg-[var(--ock-bg-inverse)]',
24+
)}
25+
onClick={handleClick}
26+
>
2027
<TokenImage token={swapUnit.token} size={36} />
2128
<div className="flex flex-col">
2229
<div>
@@ -26,7 +33,7 @@ function TokenItem({ swapUnit }: { swapUnit: SwapUnit }) {
2633
className={cn('text-xs', color.foregroundMuted)}
2734
>{`Balance: ${swapUnit.balance}`}</div>
2835
</div>
29-
</div>
36+
</button>
3037
);
3138
}
3239

@@ -38,11 +45,11 @@ export function FundSwapDropdown() {
3845
className={cn(
3946
color.foreground,
4047
background.alternate,
41-
'absolute right-0 bottom-0 flex translate-y-[110%] flex-col gap-4',
42-
'rounded p-4',
48+
'absolute right-0 bottom-0 flex translate-y-[110%] flex-col gap-2',
49+
'rounded p-2',
4350
)}
4451
>
45-
<div>Buy with</div>
52+
<div className="px-2 pt-2">Buy with</div>
4653
<TokenItem swapUnit={fromETH} />
4754
<TokenItem swapUnit={fromUSDC} />
4855
</div>

src/swap/components/FundSwapProvider.tsx

+19-10
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type {
2828
import { isSwapError } from '../utils/isSwapError';
2929
import { processSwapTransaction } from '../utils/processSwapTransaction';
3030
import { useFundSwapTokens } from '../hooks/useFundSwapTokens';
31+
import { useResetFundSwapInputs } from '../hooks/useResetFundSwapInputs';
3132

3233
const emptyContext = {} as FundSwapContextType;
3334

@@ -84,7 +85,7 @@ export function FundSwapProvider({
8485
const { sendCallsAsync } = useSendCalls(); // Atomic Batch transactions (and approval, if applicable)
8586

8687
// Refreshes balances and inputs post-swap
87-
// const resetInputs = useResetInputs({ from, to });
88+
const resetInputs = useResetFundSwapInputs({ fromETH, fromUSDC, to });
8889
// For batched transactions, listens to and awaits calls from the Wallet server
8990
const awaitCallsStatus = useAwaitCalls({
9091
accountConfig,
@@ -123,9 +124,9 @@ export function FundSwapProvider({
123124
// prevents multiple calls to `onStatus`
124125
if (lifecycleStatus.statusName === 'init' && hasHandledSuccess) {
125126
setHasHandledSuccess(false);
126-
// resetInputs();
127+
resetInputs();
127128
}
128-
}, [hasHandledSuccess, lifecycleStatus.statusName]);
129+
}, [hasHandledSuccess, lifecycleStatus.statusName, resetInputs]);
129130

130131
useEffect(() => {
131132
// For batched transactions, `transactionApproved` will contain the calls ID
@@ -145,16 +146,24 @@ export function FundSwapProvider({
145146
]);
146147

147148
useEffect(() => {
149+
let timer: NodeJS.Timeout;
148150
// Reset status to init after success has been handled
149151
if (lifecycleStatus.statusName === 'success' && hasHandledSuccess) {
150-
updateLifecycleStatus({
151-
statusName: 'init',
152-
statusData: {
153-
isMissingRequiredField: true,
154-
maxSlippage: config.maxSlippage,
155-
},
156-
});
152+
timer = setTimeout(() => {
153+
updateLifecycleStatus({
154+
statusName: 'init',
155+
statusData: {
156+
isMissingRequiredField: true,
157+
maxSlippage: config.maxSlippage,
158+
},
159+
});
160+
}, 3000);
157161
}
162+
return () => {
163+
if (timer) {
164+
return clearTimeout(timer);
165+
}
166+
};
158167
}, [
159168
config.maxSlippage,
160169
hasHandledSuccess,
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { useCallback } from 'react';
2+
import type { FundSwapTokens } from '../types';
3+
4+
// Refreshes balances and inputs post-swap
5+
export const useResetFundSwapInputs = ({
6+
fromETH,
7+
fromUSDC,
8+
to,
9+
}: FundSwapTokens) => {
10+
return useCallback(async () => {
11+
await Promise.all([
12+
fromETH.balanceResponse?.refetch(),
13+
fromUSDC.balanceResponse?.refetch(),
14+
to.balanceResponse?.refetch(),
15+
fromETH.setAmount(''),
16+
fromUSDC.setAmount(''),
17+
fromETH.setAmountUSD(''),
18+
fromUSDC.setAmountUSD(''),
19+
to.setAmount(''),
20+
to.setAmountUSD(''),
21+
]);
22+
}, [fromETH, fromUSDC, to]);
23+
};

0 commit comments

Comments
 (0)