フロントエンドを完成させよう
コンポーネントを追加しましょう
フロントエンドが完成に近づいてきました!
このレッスンでは残りのコンポーネントを実装してフロントエンドを完成させましょう。
各コンポーネント作成ごとにUIを確認していくので、AVAX-AMMディレクトリ直下にいることを確認しターミナル上で以下のコマンドを実行してください。
yarn client dev
📁 components
ディレクトリ
📁 SelectTab
ディレクトリ
components
ディレクトリ内にSelectTab
というディレクトリを作成し、
その中にSelectTab.module.css
という名前のファイルを作成してください。
SelectTab.module.css
内に以下のコードを記述してください。
.tabBody {
margin: 0px auto;
width: 460px;
padding-top: 5px;
justify-content: center;
align-items: center;
background-color: #0e0e10;
border-radius: 0px 0px 19px 19px;
border-top: 0px;
}
.bottomDiv {
margin: 10px auto;
width: 30%;
padding: 5px;
justify-content: center;
align-items: center;
border-radius: 19px;
}
.btn {
background-color: #356c93;
margin: 10px 30px;
color: white;
display: flex;
justify-content: center;
align-items: center;
font-size: 18px;
width: 100px;
height: 40px;
border-radius: 9px;
cursor: pointer;
}
.btn:hover {
background: #57adea;
}
.swapIcon {
width: 5%;
text-align: center;
display: flex;
margin: 40px auto;
color: #ff726e;
}
.estimate {
height: 30px;
width: 75%;
margin: 0px auto;
margin-top: 10px;
margin-bottom: 30px;
color: white;
}
.error {
color: white;
display: flex;
justify-content: flex-start;
padding: 0px 20px;
}
🚰 Faucet
次にSelectTab
ディレクトリ内にFaucet.tsx
という名前のファイルを作成し、以下のコードを記述してください。
import { ethers } from "ethers";
import { useEffect, useState } from "react";
import { TokenType } from "../../hooks/useContract";
import { validAmount } from "../../utils/validAmount";
import InputNumberBox from "../InputBox/InputNumberBox";
import styles from "./SelectTab.module.css";
type Props = {
token0: TokenType | undefined;
token1: TokenType | undefined;
currentAccount: string | undefined;
updateDetails: () => void;
};
export default function Faucet({
token0,
token1,
currentAccount,
updateDetails,
}: Props) {
const [amountOfFunds, setAmountOfFunds] = useState("");
const [currentTokenIndex, setCurrentTokenIndex] = useState(0);
const [tokens, setTokens] = useState<TokenType[]>([]);
useEffect(() => {
if (!token0 || !token1) return;
setTokens([token0, token1]);
}, [token0, token1]);
// tokensの範囲内で、参照するインデックスを次に移動させます。
const onChangeToken = () => {
setCurrentTokenIndex((currentTokenIndex + 1) % tokens.length);
};
const onChangeAmountOfFunds = (amount: string) => {
setAmountOfFunds(amount);
};
async function onClickFund() {
if (!currentAccount) {
alert("connect wallet");
return;
}
if (tokens.length === 0) return;
if (!validAmount(amountOfFunds)) {
alert("Amount should be a valid number");
return;
}
try {
const contract = tokens[currentTokenIndex].contract;
const amountInWei = ethers.utils.parseEther(amountOfFunds);
const txn = await contract.faucet(currentAccount, amountInWei);
await txn.wait();
updateDetails(); // ユーザとammの情報を更新
alert("Success");
} catch (error) {
console.log(error);
}
}
return (
<div className={styles.tabBody}>
<div className={styles.bottomDiv}>
<div className={styles.btn} onClick={() => onChangeToken()}>
Change
</div>
</div>
<InputNumberBox
leftHeader={
"Amount of " +
(tokens[currentTokenIndex]
? tokens[currentTokenIndex].symbol
: "some token")
}
right={
tokens[currentTokenIndex] ? tokens[currentTokenIndex].symbol : ""
}
value={amountOfFunds}
onChange={(e) => onChangeAmountOfFunds(e.target.value)}
/>
<div className={styles.bottomDiv}>
<div className={styles.btn} onClick={() => onClickFund()}>
Fund
</div>
</div>
</div>
);
}
ここではあなたがデプロイした、USDCとJOEのfaucetを実装しています。
実装の中身を見る前にブラウザ上でUIを見てみましょう。
components/Container/Container.tsx
内に以下の内容を追加してください。
import { useState } from 'react';
import { useContract } from '../../hooks/useContract';
import Details from '../Details/Details';
+ import Faucet from '../SelectTab/Faucet';
import styles from './Container.module.css';
type Props = {
currentAccount: string | undefined;
};
export default function Container({ currentAccount }: Props) {
// ...
return (
// ...
{activeTab === 'Swap' && <div>swap</div>}
{activeTab === 'Provide' && <div>provide</div>}
{activeTab === 'Withdraw' && <div>withdraw</div>}
+ {activeTab === 'Faucet' && (
+ <Faucet
+ token0={token0}
+ token1={token1}
+ currentAccount={currentAccount}
+ updateDetails={updateDetails}
+ />
+ )}
// ...
);
}
ブラウザでhttp://localhost:3000
へアクセスします。
Faucet
タブをクリックすると以下のような表示がされます。
入力欄に10と入力し、Fund
をクリックします。
トランザクションに署名し、しばらく待つと(ポップアップが表示されokを押した後)右側のYour Details
のUSDCの部分が10増えているはずです。
Change
ボタンをクリックするとUSDC -> JOEへ変更されるため、JOEに関しても同じようにfaucetを利用することができます。
それではFaucet.tsx
の中身を見ましょう。
使用する状態変数は以下の通りです。
const [amountOfFunds, setAmountOfFunds] = useState(""); // ユーザが指定した取得したいトークンの量を保持します。
const [currentTokenIndex, setCurrentTokenIndex] = useState(0); // 現在のtokens(この次にあります)のインデックスを保持します。
const [tokens, setTokens] = useState<TokenType[]>([]); // [token0, token1] のようにトークンオブジェクトが格納されます。
以下はユーザの操作によって動く関数の実装です。
// tokensの範囲内で、参照するインデックスを次に移動させます。
const onChangeToken = () => {
setCurrentTokenIndex((currentTokenIndex + 1) % tokens.length);
};
const onChangeAmountOfFunds = (amount: string) => {
setAmountOfFunds(amount);
};
async function onClickFund() {
if (!currentAccount) {
alert("connect wallet");
return;
}
if (tokens.length === 0) return;
if (!validAmount(amountOfFunds)) {
alert("Amount should be a valid number");
return;
}
try {
const contract = tokens[currentTokenIndex].contract;
const amountInWei = ethers.utils.parseEther(amountOfFunds);
const txn = await contract.faucet(currentAccount, amountInWei);
await txn.wait();
updateDetails(); // ユーザとammの情報を更新
alert("Success");
} catch (error) {
console.log(error);
}
}
onChangeToken
:Change