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/account #16

Merged
merged 14 commits into from
Dec 9, 2023
3 changes: 1 addition & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ module.exports = {
'dist',
'build',
'public/**',
'next-env.d.ts',
'libs/types/*',
'next-env.d.ts'
],
};
6,891 changes: 5,220 additions & 1,671 deletions package-lock.json

Large diffs are not rendered by default.

34 changes: 18 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,27 @@
"truffle:migrate": "truffle migrate",
"smart-contracts:typechain:generate": "typechain --target=truffle-v5 --out-dir src/types/typechain-dir-out/truffle 'src/truffle/build/*.json'",
"app:typechain:generate": "npx typechain --target ethers-v6 --out-dir src/types/typechain-dir-out/app 'src/truffle/build/*.json'",
"next:dev": "next dev",
"next:build": "next build",
"lint": "eslint --ext .js,.jsx,.ts,.tsx .",
"lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix",
"dev": "next dev",
"start": "next start -H 0.0.0.0 -p 3000",
"build": "truffle compile && npm run smart-contracts:typechain:generate && npm run app:typechain:generate && npm run next:build"
"build": "truffle compile && npm run smart-contracts:typechain:generate && npm run app:typechain:generate && next build"
},
"dependencies": {
"@metamask/providers": "^14.0.2",
"@openzeppelin/contracts": "^5.0.0",
"@tanstack/react-query": "^5.12.2",
"@tanstack/react-query-devtools": "^5.13.3",
"@tanstack/react-query-next-experimental": "^5.12.2",
"@typechain/ethers-v6": "^0.5.1",
"@typechain/truffle-v5": "^8.0.7",
"@types/chai": "^4.3.11",
"@types/mocha": "^10.0.6",
"autoprefixer": "^10.4.16",
"axios": "^1.6.2",
"bufferutil": "^4.0.8",
"daisyui": "^4.4.19",
"ethers": "^6.9.0",
"formik": "^2.4.5",
"next": "^13.5.6",
"postcss": "^8.4.32",
Expand All @@ -39,39 +46,34 @@
"react-hot-toast": "^2.4.1",
"tailwindcss": "^3.3.6",
"theme-change": "^2.5.0",
"utf-8-validate": "^6.0.3",
"ws": "^8.14.2",
"yup": "^1.3.2",
"@openzeppelin/contracts": "^5.0.0",
"@typechain/truffle-v5": "^8.0.7",
"@types/chai": "^4.3.11",
"@types/mocha": "^10.0.6",
"truffle": "^5.5.19",
"ts-node": "^10.9.1",
"typechain": "^8.3.2",
"ethers": "^6.9.0",
"@typechain/ethers-v6": "^0.5.1"
"utf-8-validate": "^6.0.3",
"wagmi": "^1.4.10",
"ws": "^8.14.2",
"yup": "^1.3.2"
},
"devDependencies": {
"@next/eslint-plugin-next": "^14.0.3",
"@types/axios": "^0.14.0",
"@types/dompurify": "^3.0.4",
"@types/node": "20.10.4",
"@types/react": "18.2.13",
"@types/react-dom": "18.2.6",
"@types/yup": "^0.32.0",
"@typescript-eslint/eslint-plugin": "5.12.1",
"@typescript-eslint/parser": "^5.0.1",
"eslint": "^8.19.0",
"eslint-config-airbnb": "19.0.4",
"eslint-config-next": "12.1.6",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-jsx-a11y": "6.5.1",
"eslint-plugin-prettier": "4.0.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-promise": "6.0.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"@next/eslint-plugin-next": "^14.0.3",
"@typescript-eslint/eslint-plugin": "5.12.1",
"@typescript-eslint/parser": "^5.0.1",
"typescript": "^5.1.0"
}
}
Binary file added public/images/avatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions src/app/api/fundraisers/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export async function GET(request: Request) {
const { searchParams } = new URL(request.url);

const { limit = 0, offset = 0 } = Object.fromEntries(
searchParams.entries()
searchParams.entries(),
);

// Get the base URL from the environment
Expand All @@ -37,7 +37,7 @@ export async function GET(request: Request) {

const fundraiserFactory = FundraiserFactory__factory.connect(
config.fundraiserFactoryAddress,
provider
provider,
);

// Get total fundraisers
Expand All @@ -58,7 +58,7 @@ export async function GET(request: Request) {
},
{
status: 200,
}
},
);
}

Expand Down Expand Up @@ -90,7 +90,7 @@ export async function GET(request: Request) {
totalDonations: Number(formatEther(totalDonations)),
donationsCount: Number(donationsCount),
};
})
}),
);

const paginatedData: Paginated<FundraiserDto> = {
Expand All @@ -111,7 +111,7 @@ export async function GET(request: Request) {
{
error: error.message,
},
{ status: 500 }
{ status: 500 },
);
}
return NextResponse.json(error, { status: 500 });
Expand Down
2 changes: 1 addition & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Head from 'next/head';
import { Toaster } from 'react-hot-toast';
import { NavBar } from 'src/components/organisms';
import { NAV_LINKS } from 'src/constants';
import Providers from 'src/utils/provider';
import Providers from 'src/utils/providers';

const openSans = Open_Sans({
subsets: ['latin'],
Expand Down
6 changes: 3 additions & 3 deletions src/components/molecules/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ const Modal = forwardRef<HTMLDialogElement, Props>(
</button>
</form>
{title && <h3 className="font-bold text-lg">{title}</h3>}
{title && <h3 className="font-bold text-lg mb-4">{title}</h3>}
{description && <div className="py-4">{description}</div>}
<div className="py-4">{children}</div>
<div>{children}</div>
<div className="modal-action">{actions}</div>
</div>
<form method="dialog" className="modal-backdrop">
<button>close</button>
</form>
</dialog>
);
}
},
);

export default Modal;
66 changes: 60 additions & 6 deletions src/components/molecules/wallet.connect.button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,72 @@

import React from 'react';
import { CreditCard } from 'react-feather';
import { useWalletContext } from 'src/contexts/wallet.context';
import {
useAccount,
useBalance,
useConnect,
useDisconnect,
useEnsAvatar,
useEnsName,
useNetwork,
} from 'wagmi';
import { ButtonVariant } from 'src/enums/button.variant.enum';
import { shortenEthereumAddress } from 'src/helpers/short.address';
import { Button } from '../atoms';
import { Account } from '../organisms';
import Modal from './modal';

const WalletConnectButton = () => {
const { account, connectToWallet } = useWalletContext();
const { address, isConnected } = useAccount();
const { data } = useBalance({ address });
const { connect, connectors } = useConnect();
const { data: ensName } = useEnsName({ address });
const { data: ensAvatar } = useEnsAvatar({ name: ensName });
const { disconnect } = useDisconnect();
const { chain } = useNetwork();
const accountModalRef = React.useRef<HTMLDialogElement>(null);

function onDisconnect() {
const accountModal = accountModalRef.current;
if (accountModal && accountModal.close) {
accountModal.close();
}
disconnect();
}

function showAccountModal() {
const accountModal = accountModalRef.current;
if (accountModal && accountModal.showModal) {
accountModal.showModal();
}
}

function onClick() {
if (isConnected) {
return showAccountModal();
}
void connect({ connector: connectors[0] });
}

return (
<Button onClick={connectToWallet} variant={ButtonVariant.Secondary}>
<CreditCard />
<span>{account ? shortenEthereumAddress(account) : 'Connect'}</span>
</Button>
<>
<Button onClick={onClick} variant={ButtonVariant.Secondary}>
<CreditCard />
<span>{address ? shortenEthereumAddress(address) : 'Connect'}</span>
</Button>
{address && isConnected && (
<Modal id="account" title="Account" ref={accountModalRef}>
<Account
address={address}
balance={Number(data?.formatted)}
ensAvatar={ensAvatar}
networkId={chain?.id}
networkName={chain?.name}
onDisconnect={onDisconnect}
/>
</Modal>
)}
</>
);
};

Expand Down
88 changes: 88 additions & 0 deletions src/components/organisms/account.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import Image from 'next/image';
import React from 'react';
import { Clipboard, DollarSign, Link, LogOut } from 'react-feather';
import toast from 'react-hot-toast';
import AvatarImage from 'public/images/avatar.png';
import { ButtonVariant } from 'src/enums/button.variant.enum';
import { copyStringToClipboard } from 'src/helpers/copy.to.clipboard';
import { shortenEthereumAddress } from 'src/helpers/short.address';
import { Button } from '../atoms';

interface Props {
address: string;
balance: number;
networkId?: number;
networkName?: string;
ensAvatar?: string | null;
onDisconnect: () => void;
}

const Account: React.FC<Props> = ({
address,
balance,
ensAvatar,
networkId,
networkName,
onDisconnect,
}) => {
function onCopyAddress() {
void copyStringToClipboard(address);
toast.dismiss();
toast.success('Address copied to clipboard');
}

return (
<div>
<div className="flex">
<div className="avatar">
<div className="w-[60px] rounded-full">
<Image
src={ensAvatar || AvatarImage}
alt="avatar"
width={100}
height={100}
/>
</div>
</div>
<div>
<span className="text-sm text-gray-500">Your wallet</span>
<button
className="flex items-center ml-2 text-md cursor-pointer select-none"
onClick={onCopyAddress}
>
{shortenEthereumAddress(address)} <Clipboard height={15} />
</button>
</div>
</div>
<div className="m-4">
<div className="flex justify-between">
<div className="flex items-center">
<Link height={16} className="mr-1" /> Network
</div>
<div>
{networkId} {networkName}
</div>
</div>
<div className="flex justify-between mt-2">
<div className="flex items-center">
{' '}
<DollarSign height={16} className="mr-1" /> Balance
</div>
<div>{balance.toFixed(2)} Eth</div>
</div>
</div>
<div className="w-full flex justify-end">
<Button
className="w-full"
onClick={onDisconnect}
variant={ButtonVariant.Secondary}
>
<LogOut />
Disconnect
</Button>
</div>
</div>
);
};

export default Account;
10 changes: 6 additions & 4 deletions src/components/organisms/donation.form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { Formik, FormikHelpers } from 'formik';
import React, { ChangeEvent, FormEvent } from 'react';
import toast from 'react-hot-toast';
import { useWalletContext } from 'src/contexts/wallet.context';
import { useAccount, useBalance } from 'wagmi';
import { ButtonType } from 'src/enums/button.type.enum';
import { ButtonVariant } from 'src/enums/button.variant.enum';
import { InputType } from 'src/enums/input.type.enum';
Expand All @@ -17,10 +17,12 @@ interface Props {
}

const DonationForm: React.FC<Props> = ({ fundraiserAddress, onSubmit }) => {
const { balance } = useWalletContext();
const { address } = useAccount();
const { data: balanceData } = useBalance({ address });

const handleFormSubmit = async (
values: DonationValues,
{ setSubmitting }: FormikHelpers<DonationValues>
{ setSubmitting }: FormikHelpers<DonationValues>,
) => {
try {
const validatedValues = donationSchema.cast(values);
Expand Down Expand Up @@ -67,7 +69,7 @@ const DonationForm: React.FC<Props> = ({ fundraiserAddress, onSubmit }) => {
label="Eth Amount"
value={values.ethAmount}
min={0}
max={balance}
max={Number(balanceData?.formatted)}
disabled={isSubmitting}
step={0.01}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
Expand Down
4 changes: 2 additions & 2 deletions src/components/organisms/fundraiser.card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const FundraiserCard = forwardRef<HTMLDivElement, Props>(
goal = 0,
} = fundraiser;
const percentage = (goal > 0 ? (totalDonations / goal) * 100 : 0).toFixed(
2
2,
);
return (
<div ref={ref} className="card xs:w-80 lg:w-96 bg-base-100 shadow-xl">
Expand Down Expand Up @@ -77,7 +77,7 @@ const FundraiserCard = forwardRef<HTMLDivElement, Props>(
</CardBody>
</div>
);
}
},
);

export default FundraiserCard;
2 changes: 1 addition & 1 deletion src/components/organisms/fundraiser.form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const FundraiserForm: React.FC<Props> = ({ onSubmit }) => {

const handleFormSubmit = async (
values: FundraiserValues,
{ setSubmitting }: FormikHelpers<FundraiserValues>
{ setSubmitting }: FormikHelpers<FundraiserValues>,
) => {
try {
const validatedValues = fundraiserSchema.cast(values);
Expand Down
1 change: 1 addition & 0 deletions src/components/organisms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export { default as FundraiserForm } from './fundraiser.form';
export { default as DonationForm } from './donation.form';
export { default as IntroContent } from './intro.content';
export { default as FundraiserCard } from './fundraiser.card';
export { default as Account } from './account';
Loading