Skip to content

Commit

Permalink
refactor (balance-hooks): adjusted useBalance hook and component prop…
Browse files Browse the repository at this point in the history
…s handling

    - Fixed the useBalance hook to calculate balance accurately for both Supply and Borrow.
    - Refactored the ProfileStats component to receive the residual balance (total Supplies balance minus total Borrows balance).
    - Refactored the lending page to pass balance props using the useBalance hook to the Supplies and Borrows components.
    - Refactored the Supplies and Borrows components to receive balance props via the implemented hook on the lending main page.
  • Loading branch information
Jorge Sarricolea committed Jul 11, 2024
1 parent 2e09d7f commit d988705
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 60 deletions.
55 changes: 30 additions & 25 deletions packages/nextjs/app/lending/components/Borrows.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,26 @@
"use client";

import React from "react";
import React, { useEffect, useState } from "react";
import AssetModal from "./modals/AssetModal";
import BorrowTable from "./tables/BorrowTable";
import borrowsDataRaw from "@/data/assetsToBorrow.json";
import yourBorrowDataRaw from "@/data/yourBorrows.json";
import useApy from "@/hooks/useApy";
import useAssetOperations from "@/hooks/useAssetOperations";
import useBalance from "@/hooks/useBalance";
import useBorrowPower from "@/hooks/useBorrowPower";
import { Asset } from "@/types/assets/assets";

/**
* Component representing the borrows section, displaying user's current borrows
* and available assets to borrow, with modal functionality for borrowing actions.
*/
const assetsData: Asset[] = borrowsDataRaw.map((asset: any) => ({
...asset,
amount: Number(asset.amount),
apy: Number(asset.apy),
}));
// Define the interface for Borrows component props
interface BorrowsProps {
assetsData: Asset[];
yourBorrowData: Asset[];
setBalance: (balance: number) => void;
}

const yourBorrowData: Asset[] = yourBorrowDataRaw.map((asset: any) => ({
...asset,
amount: Number(asset.amount),
apy: Number(asset.apy),
}));
// Borrows component for displaying user's borrowed assets and available assets to borrow
const Borrows: React.FC<BorrowsProps> = ({ assetsData, yourBorrowData, setBalance }) => {
// Local state to keep track of the user's borrow balance
const [localBalance, setLocalBalance] = useState(0);

/**
* Borrows component manages and displays the user's borrowed assets and available assets to borrow.
* It provides a modal for performing borrow actions and shows relevant financial data.
*/
const Borrows: React.FC = () => {
// Destructure the return values from the custom hook for asset operations
const {
assets: assetsToBorrow,
yourAssets: yourBorrow,
Expand All @@ -45,38 +34,54 @@ const Borrows: React.FC = () => {
setTransferAmount: setBorrowAmount,
} = useAssetOperations(assetsData, yourBorrowData);

const balance = useBalance(yourBorrow);
// Calculate the average APY for the user's borrowed assets
const averageApy = useApy(yourBorrow);

// Calculate the user's borrow power based on their borrowed assets
const borrowPower = useBorrowPower(yourBorrow);

// useEffect hook to update the local and parent component's balance whenever the user's borrowed assets change
useEffect(() => {
const newBalance = yourBorrow.reduce((acc, asset) => acc + (asset.amount ?? 0), 0);
setLocalBalance(newBalance);
setBalance(newBalance);
}, [yourBorrow, setBalance]);

// Render the Borrows component
return (
<div className="rounded-md">
{/* Section for displaying the user's borrowed assets */}
<div className="w-full bg-white px-6 py-4 rounded-2xl shadow-md mb-4">
<h2 className="text-2xl text-primary font-semibold mb-2">Your Borrows</h2>
{yourBorrow.length > 0 ? (
<>
{/* Display balance, average APY, and borrow power if the user has borrowed assets */}
<div className="flex justify-between my-4 text-sm w-fit gap-2">
<span className="text-gray-500 bg-gray-200 px-2 py-1 rounded-md">Balance ${balance}</span>
<span className="text-gray-500 bg-gray-200 px-2 py-1 rounded-md">Balance ${localBalance}</span>
<span className="text-gray-500 bg-gray-200 px-2 py-1 rounded-md">
Average APY {averageApy.toFixed(2)}%
</span>
<span className="text-gray-500 bg-gray-200 px-2 py-1 rounded-md">
Borrow power used {borrowPower.toFixed(2)}
</span>
</div>
{/* Table for displaying borrowed assets */}
<BorrowTable assets={yourBorrow} isBorrowed={true} onAction={asset => openModal(asset, false)} />
</>
) : (
<p className="text-slate-800">Nothing borrowed yet</p>
)}
</div>

{/* Section for displaying available assets to borrow */}
<div className="bg-white p-6 rounded-2xl shadow-md">
<h2 className="text-xl text-primary font-semibold mb-4">Assets to Borrow</h2>
<p className="text-gray-500 mb-4">Select the asset you want to borrow against your supplies</p>
{/* Table for displaying available assets to borrow */}
<BorrowTable assets={assetsToBorrow} isBorrowed={false} onAction={asset => openModal(asset, true)} />
</div>

{/* Modal for confirming borrow actions */}
<AssetModal
isOpen={isModalOpen}
onClose={closeModal}
Expand Down
13 changes: 8 additions & 5 deletions packages/nextjs/app/lending/components/ProfileStats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ import React from "react";
import Image from "next/image";
import BaseLogo from "../../../public/Base-Logo.jpg";

const ProfileStats: React.FC = () => {
// Simulated data
interface ProfileStatsProps {
balance: number;
}

const ProfileStats: React.FC<ProfileStatsProps> = ({ balance }) => {
const data = {
netWorth: "106.04K",
netWorth: balance,
netAPY: "-3.73%",
healthFactor: 1.42,
};

return (
<header className=" bg-neutral text-white px-12 py-8 flex flex-col space-y-2 w-full m-auto">
<div className=" pl-32">
<header className="bg-neutral text-white px-12 py-8 flex flex-col space-y-2 w-full m-auto">
<div className="pl-32">
<div className="flex items-center space-x-2">
<div className="text-2xl">
<Image src={BaseLogo} alt="Base Logo" className="h-8 w-8" />
Expand Down
52 changes: 30 additions & 22 deletions packages/nextjs/app/lending/components/Supplies.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,26 @@
"use client";

import React from "react";
import React, { useEffect, useState } from "react";
import AssetModal from "./modals/AssetModal";
import SupplyTable from "./tables/SupplyTable";
import assetsDataRaw from "@/data/assetsToSupply.json";
import yourSupplyDataRaw from "@/data/yourSupplies.json";
import useApy from "@/hooks/useApy";
import useAssetOperations from "@/hooks/useAssetOperations";
import useBalance from "@/hooks/useBalance";
import useCollateralBalance from "@/hooks/useCollateralBalance";
import { Asset } from "@/types/assets/assets";

// Process raw data into typed assets
const assetsData: Asset[] = assetsDataRaw.map((asset: any) => ({
...asset,
walletBalance: Number(asset.walletBalance),
apy: Number(asset.apy),
}));
// Define the interface for Supplies component props
interface SuppliesProps {
assetsData: Asset[];
yourSupplyData: Asset[];
setBalance: (balance: number) => void;
}

const yourSupplyData: Asset[] = yourSupplyDataRaw.map((asset: any) => ({
...asset,
amount: Number(asset.walletBalance), // Ensure amount is initialized with walletBalance
apy: Number(asset.apy),
}));
// Supplies component for displaying user's supplied assets and available assets to supply
const Supplies: React.FC<SuppliesProps> = ({ assetsData, yourSupplyData, setBalance }) => {
// Local state to keep track of the user's supply balance
const [localBalance, setLocalBalance] = useState(0);

/**
* Supplies component manages and displays the user's supplied assets and available assets to supply.
* It provides a modal for performing supply actions and shows relevant financial data.
*/
const Supplies: React.FC = () => {
// Destructure the return values from the custom hook for asset operations
const {
assets: assetsToSupply,
yourAssets: yourSupply,
Expand All @@ -43,10 +35,19 @@ const Supplies: React.FC = () => {
updateYourAssets,
} = useAssetOperations(assetsData, yourSupplyData);

const balance = useBalance(yourSupply);
// Calculate the average APY for the user's supplied assets
const averageApy = useApy(yourSupply);

// Calculate the user's collateral balance based on their supplied assets
const collateralBalance = useCollateralBalance(yourSupply);

// useEffect hook to update the local and parent component's balance whenever the user's supplied assets change
useEffect(() => {
const newBalance = yourSupply.reduce((acc, asset) => acc + (asset.walletBalance ?? 0), 0);
setLocalBalance(newBalance);
setBalance(newBalance);
}, [yourSupply, setBalance]);

// Toggle collateral status for the asset
const handleCollateralToggle = (asset: Asset) => {
const updatedYourSupply = yourSupply.map(a => {
Expand All @@ -59,21 +60,25 @@ const Supplies: React.FC = () => {
updateYourAssets(updatedYourSupply);
};

// Render the Supplies component
return (
<div className="rounded-md">
{/* Section for displaying the user's supplied assets */}
<div className="w-full bg-white px-6 py-4 rounded-2xl shadow-md mb-4">
<h2 className="text-2xl text-primary font-semibold mb-2">Your Supplies</h2>
{yourSupply.length > 0 ? (
<>
{/* Display balance, average APY, and collateral balance if the user has supplied assets */}
<div className="flex justify-between my-4 text-sm w-fit gap-2">
<span className="text-gray-500 bg-gray-200 px-2 py-1 rounded-md">Balance ${balance}</span>
<span className="text-gray-500 bg-gray-200 px-2 py-1 rounded-md">Balance ${localBalance}</span>
<span className="text-gray-500 bg-gray-200 px-2 py-1 rounded-md">
Average APY {averageApy.toFixed(2)}%
</span>
<span className="text-gray-500 bg-gray-200 px-2 py-1 rounded-md">
Collateral {collateralBalance.toFixed(2)}
</span>
</div>
{/* Table for displaying supplied assets */}
<SupplyTable
assets={yourSupply}
isSupplied={true}
Expand All @@ -86,12 +91,15 @@ const Supplies: React.FC = () => {
)}
</div>

{/* Section for displaying available assets to supply */}
<div className="bg-white p-6 rounded-2xl shadow-md">
<h2 className="text-xl text-primary font-semibold mb-4">Assets to Supply</h2>
<p className="text-gray-500 mb-4">Select the asset to deposit as collateral</p>
{/* Table for displaying available assets to supply */}
<SupplyTable assets={assetsToSupply} isSupplied={false} onAction={asset => openModal(asset, true)} />
</div>

{/* Modal for confirming supply actions */}
<AssetModal
isOpen={isModalOpen}
onClose={closeModal}
Expand Down
50 changes: 47 additions & 3 deletions packages/nextjs/app/lending/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,59 @@
"use client";

import React, { useState } from "react";
import borrowsDataRaw from "@/data/assetsToBorrow.json";
import assetsDataRaw from "@/data/assetsToSupply.json";
import yourBorrowDataRaw from "@/data/yourBorrows.json";
import yourSupplyDataRaw from "@/data/yourSupplies.json";
import { Asset } from "@/types/assets/assets";
import { NextPage } from "next";
import Borrows from "~~/app/lending/components/Borrows";
import ProfileStats from "~~/app/lending/components/ProfileStats";
import Supplies from "~~/app/lending/components/Supplies";

// Dashboard component that shows the user's lending and borrowing data
const Dashboard: NextPage = () => {
// State to manage supply and borrow balances
const [supplyBalance, setSupplyBalance] = useState(0);
const [borrowBalance, setBorrowBalance] = useState(0);

// Process raw supply data into typed Asset objects
const assetsData: Asset[] = assetsDataRaw.map((asset: any) => ({
...asset,
walletBalance: Number(asset.walletBalance),
apy: Number(asset.apy),
}));

// Process raw supply data for the user's assets
const yourSupplyData: Asset[] = yourSupplyDataRaw.map((asset: any) => ({
...asset,
amount: Number(asset.walletBalance),
apy: Number(asset.apy),
}));

// Process raw borrow data into typed Asset objects
const borrowsData: Asset[] = borrowsDataRaw.map((asset: any) => ({
...asset,
amount: Number(asset.amount),
apy: Number(asset.apy),
}));

// Process raw borrow data for the user's assets
const yourBorrowData: Asset[] = yourBorrowDataRaw.map((asset: any) => ({
...asset,
amount: Number(asset.amount),
apy: Number(asset.apy),
}));

// Calculate net balance as the difference between supply and borrow balances
const netBalance = supplyBalance - borrowBalance;

return (
<div className="flex flex-col">
<ProfileStats />
<ProfileStats balance={netBalance} />
<div className="grid grid-cols-2 gap-4 w-4/5 m-auto mt-4">
<Supplies />
<Borrows />
<Supplies assetsData={assetsData} yourSupplyData={yourSupplyData} setBalance={setSupplyBalance} />
<Borrows assetsData={borrowsData} yourBorrowData={yourBorrowData} setBalance={setBorrowBalance} />
</div>
</div>
);
Expand Down
7 changes: 3 additions & 4 deletions packages/nextjs/components/SwitchTheme.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
"use client";

import { useEffect, useState } from "react";
import { useTheme } from "next-themes";
import { MoonIcon, SunIcon } from "@heroicons/react/24/outline";
Expand All @@ -13,9 +11,10 @@ export const SwitchTheme = ({ className }: { className?: string }) => {
const handleToggle = () => {
if (isDarkMode) {
setTheme("light");
return;
} else {
setTheme("dark");
}
setTheme("dark");
console.log(`Tema cambiado a ${isDarkMode ? "light" : "dark"}`);
};

useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion packages/nextjs/hooks/useBalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const useBalance = (assets: Asset[]) => {

useEffect(() => {
// Calculate the total balance by summing up the 'balance' property of each asset
const total = assets.reduce((sum, asset) => sum + (asset.balance || 0), 0);
const total = assets.reduce((sum, asset) => sum + (asset.balance || asset.amount || 0), 0);
setBalance(total);
}, [assets]);

Expand Down

0 comments on commit d988705

Please sign in to comment.