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

Feat: Deposit modal #35

Merged
merged 3 commits into from
Sep 12, 2024
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
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
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ const PageWrapper = () => {
const isIndex = pathname === '/';

return (
<body className={`font-sans flex flex-col min-h-screen ${isIndex ? 'bg-white' : 'bg-grey-light'}`}>
<div className="min-h-screen flex flex-col">
<Nav />
<main className={`max-w-screen flex-1 ${isIndex ? 'w-[74rem]' : 'w-256'}`}>
<Outlet />
</main>
<Footer />
</body>
</div>
);
};

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;
8 changes: 4 additions & 4 deletions 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 All @@ -21,7 +21,9 @@ const { title, description } = Astro.props;
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<slot />
<body class="font-sans bg-white">
<slot />
</body>
<style is:global>
html {
font-family: system-ui, sans-serif;
Expand Down Expand Up @@ -58,6 +60,4 @@ const { title, description } = Astro.props;
width: 1px;
}
</style>


</html>
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>
);
};
Loading
Loading