Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: quick transfers handling and finance components #393

Merged
merged 2 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/hooks/use-metamask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ export const useMetaMask = () => {
}
};

return { address, connecting, connect };
return { address, connecting, connect, setAddress };
};
4 changes: 2 additions & 2 deletions src/hooks/use-withdraw.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useState } from 'react';
import { useSelector } from 'react-redux';
import { encodeFunctionData, parseUnits } from 'viem';
import { Address, encodeFunctionData, parseUnits } from 'viem';
import LedgerVaultAbi from '@src/config/abi/LedgerVault.json';
import { GLOBAL_CONSTANTS } from '@src/config-global';
import { useWeb3Session } from '@src/hooks/use-web3-session.ts';
import { ERRORS } from '@notifications/errors.ts';

interface WithdrawParams {
recipient: string;
recipient: Address;
amount: number;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ interface FinanceDepositFromMetamaskProps {
const FinanceDepositFromMetamask: FC<FinanceDepositFromMetamaskProps> = ({ onClose }) => {
const sessionData = useSelector((state: any) => state.auth.session);
const depositHook = useDepositMetamask();
const { address, connecting, connect } = useMetaMask();
const { address, connecting, connect, setAddress } = useMetaMask();

if (connecting) return <FinanceMetamaskLoader />;
if (!address) return <FinanceMetamaskButton connect={connect} />;

return <FinanceDeposit address={address} recipient={sessionData?.address} depositHook={depositHook} onClose={onClose} />;
return <FinanceDeposit address={address} recipient={sessionData?.address} depositHook={depositHook} onClose={onClose} onChangeWallet={setAddress} />;
};

export default FinanceDepositFromMetamask;
10 changes: 8 additions & 2 deletions src/sections/finance/components/finance-deposit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ interface FinanceDepositProps {
* Callback for closing the modal / dialog.
*/
onClose: () => void;

/**
* Callback to change the new address.
*/
onChangeWallet?: (address: Address) => void;
}

/**
Expand All @@ -57,7 +62,7 @@ interface FinanceDepositProps {
* - `depositHook` (generic or Metamask deposit hook)
* - `onClose`
*/
const FinanceDeposit: FC<FinanceDepositProps> = ({ address, recipient, depositHook, onClose }) => {
const FinanceDeposit: FC<FinanceDepositProps> = ({ address, recipient, depositHook, onClose, onChangeWallet }) => {
const [amount, setAmount] = useState<number>();
const [helperText, setHelperText] = useState<string>("");
const { balance } = useGetMmcContractBalance(address);
Expand Down Expand Up @@ -152,7 +157,7 @@ const FinanceDeposit: FC<FinanceDepositProps> = ({ address, recipient, depositHo
sx={{ mt: 1 }}
fullWidth
autoFocus
label="Amount to withdraw"
label="Amount to deposit"
type="number"
value={amount}
onChange={handleAmountChange}
Expand All @@ -170,6 +175,7 @@ const FinanceDeposit: FC<FinanceDepositProps> = ({ address, recipient, depositHo
balance={balance ?? 0}
label={'Confirm'}
onConfirmAction={handleConfirmDeposit}
onChangeWallet={onChangeWallet}
onCloseAction={onClose}
/>
</>
Expand Down
40 changes: 25 additions & 15 deletions src/sections/finance/components/finance-quick-transfer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import Box from '@mui/material/Box';
import CardHeader from '@mui/material/CardHeader';
import { CardProps } from '@mui/material/Card';

// Project components
// LOCAL IMPORTS
import { useBoolean } from '@src/hooks/use-boolean';
import Carousel, { CarouselArrows, useCarousel } from '@src/components/carousel';
import NeonPaper from '@src/sections/publication/NeonPaperContainer.tsx';
Expand All @@ -35,7 +35,6 @@ import FinanceSearchProfileModal from '@src/sections/finance/components/finance-

const STEP = 50;
const MIN_AMOUNT = 0;
const AVATAR_SIZE = 40;

interface Props extends CardProps {
title?: string;
Expand Down Expand Up @@ -72,6 +71,7 @@ export default function FinanceQuickTransfer({
const [initialized, setInitialized] = useState(false);
const [list, setList] = useState<Profile[]>(initialList ?? []);
const [amount, setAmount] = useState(0);
const [canContinue, setCanContinue] = useState(true);

const confirm = useBoolean();
const MAX_AMOUNT = balance;
Expand Down Expand Up @@ -107,7 +107,6 @@ export default function FinanceQuickTransfer({
centerMode: true,
swipeToSlide: true,
infinite: true,
focusOnSelect: true,
centerPadding: '0px',
rows: 1,
slidesToShow: list?.length > 7 ? 7 : (list?.length ?? 1),
Expand Down Expand Up @@ -153,7 +152,7 @@ export default function FinanceQuickTransfer({
if (currentProfile?.ownedBy?.address) {
const profileId = currentProfile.id
const address = currentProfile.ownedBy.address;

setWalletAddress(address);
dispatch(storeAddress({ address, profileId }));
}
Expand Down Expand Up @@ -198,25 +197,31 @@ export default function FinanceQuickTransfer({
// Handle changes in the slider
const handleChangeSlider = useCallback((_event: Event, newValue: number | number[]) => {
setAmount(newValue as number);
}, []);
if(newValue < MAX_AMOUNT) {
setCanContinue(true);
}
}, [MAX_AMOUNT]);

// Handle changes in the input for the amount
const handleChangeInput = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
setAmount(Number(event.target.value));

// Send the focus back to the input field, this is a workaround for the slider carousel
setTimeout(() => {
event.target.focus();
}, 25);

if(Number(event.target.value) < MAX_AMOUNT) {
setCanContinue(true);
}else{
setCanContinue(false);
}
}, []);

// Validate the amount on blur
const handleBlur = useCallback(() => {
if(amount < MAX_AMOUNT) {
setCanContinue(true);
}

if (amount < 0) {
setAmount(0);
} else if (amount > MAX_AMOUNT) {
setAmount(MAX_AMOUNT);
setCanContinue(false);
}
}, [amount, MAX_AMOUNT]);

Expand All @@ -228,6 +233,11 @@ export default function FinanceQuickTransfer({
dispatch(storeAddress({ address: '', profileId: '' }));
};

// Handle onClick for carousel items
const handleCarouselClick = (index: number) => {
carousel.setCurrentIndex(index);
};

// If the stored address changes or if we typed a valid custom address, check if it exists in the carousel
useEffect(() => {
// Attempt to match the stored address + profileId
Expand Down Expand Up @@ -318,7 +328,7 @@ export default function FinanceQuickTransfer({
}}
>
{list?.map((profile, index) => (
<Box key={profile.id} sx={{ py: 2 }}>
<Box key={profile.id} sx={{ py: 2 }} onClick={ () => handleCarouselClick(index)}>
<Tooltip
key={profile.id}
title={profile?.metadata?.displayName}
Expand Down Expand Up @@ -368,7 +378,7 @@ export default function FinanceQuickTransfer({
/>

<Slider
color="secondary"
color={canContinue ? 'secondary' : 'warning'}
value={amount ?? 0}
valueLabelDisplay="auto"
step={STEP}
Expand All @@ -389,7 +399,7 @@ export default function FinanceQuickTransfer({
size="large"
color="inherit"
variant="contained"
disabled={amount === 0 || !isValidAddress(walletAddress)}
disabled={amount === 0 || !isValidAddress(walletAddress) || !canContinue}
onClick={confirm.onTrue}
>
Transfer Now
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,23 @@ import { FC } from 'react';

// LOCAL IMPORTS
import { useMetaMask } from '@src/hooks/use-metamask';
import { useWithdrawMetamask } from '@src/hooks/use-withdraw-metamask';
import { useGetVaultBalance } from '@src/hooks/use-get-vault-balance';
import FinanceWithdraw from '@src/sections/finance/components/finance-withdraw';
import FinanceMetamaskLoader from '@src/sections/finance/components/finance-metamask-loader.tsx';
import FinanceMetamaskButton from '@src/sections/finance/components/finance-metamask-button.tsx';
import { useWithdraw } from '@src/hooks/use-withdraw.ts';

interface FinanceWithdrawFromMetamaskProps {
onClose: () => void;
}

const FinanceWithdrawFromMetamask: FC<FinanceWithdrawFromMetamaskProps> = ({ onClose }) => {
const withdrawHook = useWithdrawMetamask();
const { address, connecting, connect } = useMetaMask();
const { balance } = useGetVaultBalance(address);
const withdrawHook = useWithdraw();
const { address, connecting, connect, setAddress } = useMetaMask();

if (connecting) return <FinanceMetamaskLoader />;
if (!address) return <FinanceMetamaskButton connect={connect} />;

return <FinanceWithdraw address={address} withdrawHook={withdrawHook} balance={balance} onClose={onClose} />;
return <FinanceWithdraw address={address} withdrawHook={withdrawHook} onClose={onClose} onChangeWallet={setAddress} />;
};

export default FinanceWithdrawFromMetamask;
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { FC } from 'react';
import { useWithdraw } from '@src/hooks/use-withdraw';
import { useGetBalance } from '@src/hooks/use-get-balance';
import { useSelector } from 'react-redux';
import FinanceWithdraw from './finance-withdraw';

Expand All @@ -11,14 +10,12 @@ interface FinanceWithdrawFromSmartAccountProps {
const FinanceWithdrawFromSmartAccount: FC<FinanceWithdrawFromSmartAccountProps> = ({ onClose }) => {
const sessionData = useSelector((state: any) => state.auth.session);
const userAddress = sessionData?.address;
const { balance } = useGetBalance();
const withdrawHook = useWithdraw();

return (
<FinanceWithdraw
address={userAddress}
withdrawHook={withdrawHook}
balance={balance}
onClose={onClose}
/>
);
Expand Down
64 changes: 10 additions & 54 deletions src/sections/finance/components/finance-withdraw.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// REACT IMPORTS
import { FC, useCallback, useEffect, useState } from 'react';

// VIEM IMPORTS
Expand All @@ -14,7 +15,6 @@ import FinanceDialogsActions from '@src/sections/finance/components/finance-dial
import TextMaxLine from '@src/components/text-max-line';
import { formatBalanceNumber } from '@src/utils/format-number';
import BoxRow from '@src/sections/finance/components/box-row';
import { isValidAddress } from '@src/sections/finance/components/finance-quick-transfer';
import { UseWithdrawHook } from '@src/hooks/use-withdraw.ts';
import { truncateAddress } from '@src/utils/wallet.ts';

Expand All @@ -23,25 +23,25 @@ import { notifyError, notifySuccess, notifyWarning } from '@notifications/intern
import { ERRORS } from '@notifications/errors';
import { WARNING } from '@notifications/warnings';
import { SUCCESS } from '@notifications/success';
import { useGetBalance } from '@src/hooks/use-get-balance.ts';

// ----------------------------------------------------------------------

interface FinanceWithdrawProps {
address?: Address; // The connected wallet address
address: Address; // The connected wallet address
withdrawHook: UseWithdrawHook; // Generic withdraw hook
balance: number | null; // Current user balance
onClose: () => void; // Callback to close the modal/dialog
onChangeWallet?: (address: Address) => void; // Callback to change the new address.
}

// ----------------------------------------------------------------------

const FinanceWithdraw: FC<FinanceWithdrawProps> = ({ address, withdrawHook, balance, onClose }) => {
const FinanceWithdraw: FC<FinanceWithdrawProps> = ({ address, withdrawHook, onClose, onChangeWallet }) => {
const [amount, setAmount] = useState<number>();
const [destinationAddress, setDestinationAddress] = useState('');
const [addressError, setAddressError] = useState(false);
const [amountError, setAmountError] = useState(false);
const [amountHelperText, setAmountHelperText] = useState(''); // Dynamic helper text for amount
const [amountHelperText, setAmountHelperText] = useState('');
const [localLoading, setLocalLoading] = useState(false);
const { balance } = useGetBalance();
const { withdraw, loading: withdrawLoading, error } = withdrawHook;
const RainbowEffect = localLoading || withdrawLoading ? NeonPaper : Box;

Expand All @@ -54,25 +54,21 @@ const FinanceWithdraw: FC<FinanceWithdrawProps> = ({ address, withdrawHook, bala
const handleConfirmWithdraw = useCallback(async () => {
if (!amount) return;

if (!destinationAddress || addressError) {
notifyWarning(WARNING.INVALID_WALLET_ADDRESS);
return;
}
if (amount <= 0 || amount > (balance ?? 0)) {
notifyWarning(WARNING.INVALID_WITHDRAW_AMOUNT);
return;
}
try {
setLocalLoading(true);
await withdraw({ amount, recipient: destinationAddress });
await withdraw({ amount, recipient: address });
notifySuccess(SUCCESS.WITHDRAW_SUCCESSFULLY);
onClose();
} catch (err: any) {
notifyError(ERRORS.WITHDRAW_FAILED_ERROR);
} finally {
setLocalLoading(false);
}
}, [amount, destinationAddress, balance, withdraw, addressError, onClose]);
}, [amount, balance]);

const handleAmountChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = Number(event.target.value);
Expand All @@ -90,12 +86,6 @@ const FinanceWithdraw: FC<FinanceWithdrawProps> = ({ address, withdrawHook, bala
setAmountHelperText(errorMessage);
};

const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value;
setDestinationAddress(value);
setAddressError(!isValidAddress(value));
};

return (
<>
<Stack
Expand Down Expand Up @@ -137,41 +127,6 @@ const FinanceWithdraw: FC<FinanceWithdrawProps> = ({ address, withdrawHook, bala
error={amountError}
helperText={amountHelperText}
/>

<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
position: 'relative',
width: '100%',
my: 2
}}
>
<Box sx={{ background: 'rgba(255,255,255,0.1)', height: '1px', width: '100%' }} />
<Box sx={{
position: 'absolute',
left: 'calc(50% - 1.5rem)',
top: '-22px',
width: '3rem',
padding: '8px',
background: '#212b36',
textAlign: 'center',
color: 'text.secondary'
}}>
to
</Box>
</Box>

<TextField
fullWidth
label="Wallet Address"
value={destinationAddress}
onChange={handleInputChange}
placeholder="Enter wallet address"
error={addressError}
helperText={addressError ? 'Invalid wallet address' : ''}
/>
</Stack>

<FinanceDialogsActions
Expand All @@ -183,6 +138,7 @@ const FinanceWithdraw: FC<FinanceWithdrawProps> = ({ address, withdrawHook, bala
label={'Confirm'}
onConfirmAction={handleConfirmWithdraw}
onCloseAction={onClose}
onChangeWallet={onChangeWallet}
/>
</>
);
Expand Down
Loading