Skip to content

Commit

Permalink
feat: Add deposit modal, install DaisyUI
Browse files Browse the repository at this point in the history
  • Loading branch information
kovipu committed Sep 12, 2024
1 parent 85aebf9 commit d30bba3
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 38 deletions.
74 changes: 71 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
"devDependencies": {
"@biomejs/biome": "1.8.3",
"@vitejs/plugin-basic-ssl": "^1.1.0",
"daisyui": "^4.12.10",
"dotenv": "^16.4.5",
"postcss": "^8.4.45",
"prettier": "^3.3.3",
"prettier-plugin-astro": "^0.14.1"
},
Expand Down
9 changes: 5 additions & 4 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import type { PropsWithChildren } from 'react';
import { Link } from 'react-router-dom';

export interface ButtonProps {
onClick: () => void;
onClick?: () => void;
className?: string;
disabled?: boolean;
}

const buttonStyle = 'bg-black font-semibold text-white rounded-full px-8 py-2 hover:bg-grey-dark transition';
const buttonStyle = 'btn btn-neutral font-semibold text-base rounded-full px-8 py-2';

export const Button = ({ onClick, className = '', children }: PropsWithChildren<ButtonProps>) => (
<button type="button" onClick={onClick} className={`${buttonStyle} ${className}`}>
export const Button = ({ onClick, disabled = false, className = '', children }: PropsWithChildren<ButtonProps>) => (
<button type="button" onClick={onClick} disabled={disabled} className={`${buttonStyle} ${className}`}>
{children}
</button>
);
Expand Down
5 changes: 3 additions & 2 deletions src/currencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import XLMPoolContract from '@contracts/loan_pool';
import USDCPoolContract from '@contracts/usdc_pool';
import StellarIcon from '@images/Stellar_Symbol.png';
import USDCIcon from '@images/usdc.svg';
import type { SupportedCurrency } from './stellar-wallet';

export type Currency = {
name: string;
symbol: string; // could be a type union of currency symbols.
symbol: SupportedCurrency;
icon: string;
loanPoolContract: typeof XLMPoolContract;
};
Expand All @@ -23,4 +24,4 @@ export const CURRENCIES: Currency[] = [
icon: USDCIcon.src,
loanPoolContract: USDCPoolContract,
},
];
] as const;
2 changes: 1 addition & 1 deletion src/layouts/Layout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const { title, description } = Astro.props;
---

<!doctype html>
<html lang="en">
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="description" content={description} />
Expand Down
6 changes: 6 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
107 changes: 107 additions & 0 deletions src/pages/_lend/DepositModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { Button } from '@components/Button';
import { type ChangeEvent, useState } from 'react';
import type { Currency } from 'src/currencies';
import { useWallet } from 'src/stellar-wallet';

export interface DepositModalProps {
modalId: string;
onClose: () => void;
currency: Currency;
}

export const DepositModal = ({ modalId, onClose, currency }: DepositModalProps) => {
const { loanPoolContract, name, symbol } = currency;

const { wallet, balances, signTransaction } = useWallet();
const [isDepositing, setIsDepositing] = useState(false);
const [amount, setAmount] = useState('0');

const balance = balances[symbol];

if (!balance) return null;

const handleDepositClick = async () => {
if (!wallet) {
alert('Please connect your wallet first!');
return;
}

setIsDepositing(true);

loanPoolContract.options.publicKey = wallet.address;

// Multiply by ten million by adding zeroes.
const stroops = BigInt(amount) * BigInt(10_000_000);

const tx = await loanPoolContract.deposit({
user: wallet.address,
amount: stroops,
});

try {
const { result } = await tx.signAndSend({ signTransaction });
alert(`Deposit successful, result: ${result}`);
onClose();
} catch (err) {
alert(`Error depositing: ${JSON.stringify(err)}`);
}
setIsDepositing(false);
};

const handleAmountChange = (ev: ChangeEvent<HTMLInputElement>) => {
setAmount(ev.target.value);
};

return (
<dialog id={modalId} className="modal">
<div className="modal-box">
<h3 className="font-bold text-lg mb-8">Deposit {name}</h3>

<div className="flex flex-row items-center">
<div className="w-full">
<p className="text-lg mb-2">Amount to deposit</p>
<input
type="range"
min={0}
max={balance.balance}
value={amount}
className="range"
onChange={handleAmountChange}
/>
<div className="flex w-full justify-between px-2 text-xs">
<span>|</span>
<span>|</span>
<span>|</span>
<span>|</span>
<span>|</span>
</div>
</div>
</div>

<p>
{amount} {symbol} out of {balance.balance} {symbol}
</p>

<div className="flex flex-row justify-end mt-8">
<Button onClick={onClose} className="btn-ghost mr-4">
Cancel
</Button>
{!isDepositing ? (
<Button disabled={amount === '0'} onClick={handleDepositClick}>
Deposit
</Button>
) : (
<Button disabled>
<span className="loading loading-spinner" />
Depositing
</Button>
)}
</div>
</div>
{/* Invisible backdrop that closes the modal on click */}
<form method="dialog" className="modal-backdrop">
<button type="button">close</button>
</form>
</dialog>
);
};
49 changes: 33 additions & 16 deletions src/pages/_lend/LendableAssetCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,26 @@ import type { xdr } from '@stellar/stellar-base';
import { Api as RpcApi } from '@stellar/stellar-sdk/rpc';
import { useCallback, useEffect, useState } from 'react';
import type { Currency } from 'src/currencies';
import { useWallet } from 'src/stellar-wallet';
import { type Balance, useWallet } from 'src/stellar-wallet';
import { DepositModal } from './DepositModal';

export interface LendableAssetCardProps {
currency: Currency;
}

const DEPOSIT_MODAL_ID = 'modal-id';

export const LendableAssetCard = ({ currency }: LendableAssetCardProps) => {
const { icon, name, symbol, loanPoolContract } = currency;
const { wallet, signTransaction } = useWallet();
const { wallet, balances } = useWallet();

const [totalSupplied, setTotalSupplied] = useState<bigint | null>(null);
const [totalSuppliedPrice, setTotalSuppliedPrice] = useState<bigint | null>(null);

const balance: Balance | undefined = balances[symbol];

const isPoor = !balance?.balance || balance.balance === '0';

const fetchAvailableContractBalance = useCallback(async () => {
if (!loanPoolContract) return;

Expand Down Expand Up @@ -103,23 +110,24 @@ export const LendableAssetCard = ({ currency }: LendableAssetCardProps) => {
return () => clearInterval(intervalId);
}, [fetchAvailableContractBalance, fetchPriceData]); // Now dependent on the memoized function

const handleDepositClick = async () => {
const buttonLabel = (): string => {
if (!wallet) {
alert('Please connect your wallet first!');
return;
return 'Connect a wallet first.';
}
if (isPoor) {
return 'Not enough funds in the wallet.';
}
return '';
};

loanPoolContract.options.publicKey = wallet.address;

const amount = BigInt(2000000);
const tx = await loanPoolContract.deposit({ user: wallet.address, amount });
const openModal = () => {
const modalEl = document.getElementById(DEPOSIT_MODAL_ID) as HTMLDialogElement;
modalEl.showModal();
};

try {
const { result } = await tx.signAndSend({ signTransaction });
alert(`Deposit successful, result: ${result}`);
} catch (err) {
alert(`Error depositing: ${JSON.stringify(err)}`);
}
const closeModal = () => {
const modalEl = document.getElementById(DEPOSIT_MODAL_ID) as HTMLDialogElement;
modalEl.close();
fetchAvailableContractBalance();
};

Expand All @@ -143,7 +151,16 @@ export const LendableAssetCard = ({ currency }: LendableAssetCardProps) => {
<p className="text-xl font-semibold leading-6">1.23%</p>
</div>

{wallet && <Button onClick={handleDepositClick}>Deposit</Button>}
{isPoor ? (
<div className="tooltip" data-tip={!wallet ? 'Connect a wallet first' : 'Not enough funds'}>
<Button disabled={true} onClick={() => {}}>
Deposit
</Button>
</div>
) : (
<Button onClick={openModal}>Deposit</Button>
)}
<DepositModal modalId={DEPOSIT_MODAL_ID} onClose={closeModal} currency={currency} />
</Card>
);
};
Loading

0 comments on commit d30bba3

Please sign in to comment.