コレクティブル ポータル作成の最終ステップへようこそ! (パート 1 については、こちらを参照してください)
このパートでは、パズルの最後のピースであるフロントエンドの構築に焦点を当てます。
達成することは次のとおりです。
Next.js を使用してフロントエンドを構築します。
始めましょう!
プロジェクトのflow-collectible-portal
ディレクトリを開きます。それから、走ってください
ターミナルでnpx create-next-app@latest frontend
と入力し、 enter
を押します。
これにより、いくつかのオプションが提供されます。このチュートリアルでは、 Typescript 、 ESLint 、またはTailwindCSSを使用せず、この記事の時点ではsrc
ディレクトリと App ルーターを使用します。
これで、新しい Web アプリが準備できました。
フロントエンド フォルダーは次のようになります。
Flow ブロックチェーンと対話するには、Flow クライアント ライブラリ (FCL) を使用してウォレット接続を管理し、スクリプトを実行し、アプリケーションでトランザクションを送信します。これにより、完全な Cadence 関数を作成し、JavaScript 関数として実行できるようになります。
まず、次のコマンドを実行してアプリの FCL をインストールしましょう。
npm install @onflow/fcl --save
FCL をインストールした後、それを構成する必要があります。行う必要があるのは次のとおりです。
app
フォルダー内にflow
という名前の新しいフォルダーを作成し、 config.js
という名前のファイルを追加します。
次のコードをconfig.js
ファイルに追加します。
import { config } from "@onflow/fcl"; config({ "app.detail.title": "Flow Name Service", "app.detail.icon": "https://placekitten.com/g/200/200", "accessNode.api": "https://rest-testnet.onflow.org", "discovery.wallet": "https://fcl-discovery.onflow.org/testnet/authn", "0xCollectibles": "ADD YOUR CONTRACT ACCOUNT ADDRESS", "0xNonFungibleToken": "0x631e88ae7f1d7c20", });
これで、アプリで FCL を使用するための設定がすべて完了しました。
アプリでユーザーの ID を確認するには、いくつかの関数を使用できます。
fcl.logIn()
を呼び出します。fcl.signUp()
を呼び出します。fcl.unauthenticate()
を呼び出します。
これらのfcl
関数をフロントエンドに実装する方法を学びましょう。
まず、app ディレクトリ内のpage.js
ファイルに次のコードを追加します。これにより、いくつかの依存関係がインポートされ、アプリの一部に初期useState
が設定され、基本的な UI が構築されます。
見栄えを良くするには、アプリ ディレクトリ内のpage.module.css
ファイルを削除し、代わりに page.css というファイルを作成します。次に、このファイルの内容をその中に貼り付けます。これで、最初のページを書き出すことができます。
"use client"; import React, { useState, useEffect, useRef } from "react"; import * as fcl from "@onflow/fcl"; import "./page.css"; import "./flow/config"; export default function Page() { const [currentUser, setCurrentUser] = useState({ loggedIn: false, addr: undefined, }); const urlInputRef = useRef(); const nameInputRef = useRef(); const idInputRef = useRef(); const [isInitialized, setIsInitialized] = useState(); const [collectiblesList, setCollectiblesList] = useState([]); const [loading, setLoading] = useState(false); const [ids, setIds] = useState([]); const [nft, setNFT] = useState({}); useEffect(() => fcl.currentUser.subscribe(setCurrentUser), []); function handleInputChange(event) { const inputValue = event.target.value; if (/^\d+$/.test(inputValue)) { idInputRef.current = +inputValue; } else { console.error("Invalid input. Please enter a valid integer."); } } return ( <div> <div className="navbar"> <h1>Flow Collectibles Portal</h1> <span>Address: {currentUser?.addr ?? "NO Address"}</span> <button onClick={currentUser.addr ? fcl.unauthenticate : fcl.logIn}> {currentUser.addr ? "Log Out" : "Connect Wallet"} </button> </div> {currentUser.loggedIn ? ( <div className="main"> <div className="mutate"> <h1>Mutate Flow Blockchain</h1> <form onSubmit={(event) => { event.preventDefault(); }} > <input type="text" placeholder="enter name of the NFT" ref={nameInputRef} /> <input type="text" placeholder="enter a url" ref={urlInputRef} /> <button type="submit">Mint</button> </form> <mark>Your Collection will be initialized while minting NFT.</mark> </div> <div className="query"> <h1>Query Flow Blockchain</h1> <mark>Click below button to check 👇</mark> <button>Check Collection</button> <p> Is your collection initialized: {isInitialized ? "Yes" : "No"} </p> <button onClick={viewIds}> View NFT IDs you hold in your collection </button> <p>NFT Id: </p> </div> <div className="view"> <h1>View Your NFT</h1> <input type="text" placeholder="enter your NFT ID" onChange={handleInputChange} /> <button>View NFT</button> <div className="nft-card"> <p>NFT id: </p> <p>NFT name: </p> <img src="" alt="" /> </div> </div> </div> ) : ( <div className="main-2"> <h1>Connect Wallet to mint NFT!!</h1> </div> )} </div> ); }
このコードを追加した後、 npm run dev
実行して、すべてが正しく読み込まれることを確認します。
fcl
を使用して Flow ブロックチェーンをクエリする方法を詳しく説明する前に、 page.js
ファイルのhandleInput
関数の後に次の Cadence スクリプト コードを追加します。
const CHECK_COLLECTION = ` import NonFungibleToken from 0xNonFungibleToken import Collectibles from 0xCollectibles pub fun main(address: Address): Bool? { return Collectibles.checkCollection(_addr: address) }` const GET_NFT_ID = ` import NonFungibleToken from 0xNonFungibleToken import Collectibles from 0xCollectibles pub fun main(user: Address): [UInt64] { let collectionCap = getAccount(user).capabilities.get <&{Collectibles.CollectionPublic}>(/public/NFTCollection) ?? panic("This public capability does not exist.") let collectionRef = collectionCap.borrow()! return collectionRef.getIDs() } ` const GET_NFT = ` import NonFungibleToken from 0xNonFungibleToken import Collectibles from 0xCollectibles pub fun main(user: Address, id: UInt64): &NonFungibleToken.NFT? { let collectionCap= getAccount(user).capabilities.get<&{Collectibles.CollectionPublic}>(/public/NFTCollection) ?? panic("This public capability does not exist.") let collectionRef = collectionCap.borrow()! return collectionRef.borrowNFT(id: id) }
Cadence スクリプトの準備が整ったので、いくつかの Javascript 関数を宣言し、Cadence 定数を`fcl`
クエリに渡すことができます。
async function checkCollectionInit() { const isInit = await fcl.query({ cadence: CHECK_COLLECTION, args: (arg,t) => [arg(currentUser?.addr, t.Address)], }); console.log(isInit); } async function viewNFT() { console.log(idInputRef.current); const nfts = await fcl.query({ cadence: GET_NFT, args: (arg,t) => [arg(currentUser?.addr,t.Address), arg(idInputRef.current, t.UInt64)] }); setNFT(nfts); console.log(nfts); } async function viewIds() { const ids = await fcl.query({ cadence: GET_NFT_ID, args: (arg,t) => [arg(currentUser?.addr,t.Address)] }); setIds(ids); console.log(ids); }
それでは、作成したすべての関数を見てみましょう。注意すべき点が 2 つあります。
fcl.query
args: (arg,t) => [arg(addr,t.Address)],
行。
スクリプトは Solidity のview
関数に似ており、実行にガス料金を必要としないため、基本的にはブロックチェーンにクエリを実行するだけです。そこで、 fcl.query
を使用して Flow 上でスクリプトを実行します。
何かをクエリするには、引数を渡す必要があります。そのために、引数を表す文字列値を取る関数である arg と、Cadence が持つさまざまなデータ型をすべて含むオブジェクトであるt
を使用します。したがって、渡す引数をエンコードおよびデコードする方法をarg
に伝えることができます。
以前の関数は単なる「読み取り専用」でしたが、次の関数にはブロックチェーンの状態を変更して書き込みできるアクションが含まれます。別名「NFTのミント」。
これを行うには、定数として別の Cadence スクリプトを作成します。
const MINT_NFT = ` import NonFungibleToken from 0xNonFungibleToken import Collectibles from 0xCollectibles transaction(name:String, image:String){ let receiverCollectionRef: &{NonFungibleToken.CollectionPublic} prepare(signer:AuthAccount){ // initialise account if signer.borrow<&Collectibles.Collection>(from: Collectibles.CollectionStoragePath) == nil { let collection <- Collectibles.createEmptyCollection() signer.save(<-collection, to: Collectibles.CollectionStoragePath) let cap = signer.capabilities.storage.issue<&{Collectibles.CollectionPublic}>(Collectibles.CollectionStoragePath) signer.capabilities.publish( cap, at: Collectibles.CollectionPublicPath) } //takes the receiver collection refrence self.receiverCollectionRef = signer.borrow<&Collectibles.Collection>(from: Collectibles.CollectionStoragePath) ?? panic("could not borrow Collection reference") } execute{ let nft <- Collectibles.mintNFT(name:name, image:image) self.receiverCollectionRef.deposit(token: <-nft) } }
次に、 page.js
ファイルのトランザクション コードの後に以下の関数を追加します。
async function mint() { try{ const txnId = await fcl.mutate({ cadence: MINT_NFT, args: (arg,t) => [arg(name,t.String), arg(image, t.String)], payer: fcl.authz, proposer: fcl.authz, authorizations: [fcl.authz], limit:999,}); } catch(error){ console.error('Minting failed:' error) } console.log(txnId); }
関数に関しては、 fcl.mutate
構文はfcl.query
と同じです。ただし、次のような追加のパラメーターがいくつか提供されています。
payer: fcl.authz, proposer: fcl.authz, authorizations: [fcl.authz], limit: 50,
fcl.authz
現在接続されているアカウントを指します。limit
、イーサリアムの世界における GasLimit に似ており、最大計算量に上限を設けます。計算が制限を超えると、トランザクションは失敗します。
先ほど作成したmintNFT
関数を呼び出して処理する関数をもう 1 つ追加する必要があります。
const saveCollectible = async () => { if (urlInputRef.current.value.length > 0 && nameInputRef.current.value.length > 0) { try { setLoading(true); const transaction = await mintNFT(nameInputRef.current.value, urlInputRef.current.value); console.log('transactionID:', transaction); // Handle minting success (if needed) } catch (error) { console.error('Minting failed:', error); // Handle minting failure (if needed) } finally { setLoading(false); } } else { console.log('Empty input. Try again.'); } };
主要な関数を配置したら、それらを UI にプラグインできるようになります。
ただし、その前に、初期状態を読み込むのに役立つuseEffect
呼び出しをいくつか追加します。これらは、既存のuseEffect
呼び出しのすぐ上に追加できます。
useEffect(() => { checkCollectionInit(); viewNFT(); }, [currentUser]); useEffect(() => { if (currentUser.loggedIn) { setCollectiblesList(collectiblesList); console.log('Setting collectibles...'); } }, [currentUser]);
UI を含むreturn
セクションに戻り、アプリの適切な部分に関数を追加できます。
return ( <div> <div className="navbar"> <h1>Flow Collectibles Portal</h1> <span>Address: {currentUser?.addr ?? "NO Address"}</span> <button onClick={currentUser.addr ? fcl.unauthenticate : fcl.logIn}> {currentUser.addr ? "Log Out" : "Connect Wallet"} </button> </div> {currentUser.loggedIn ? ( <div className="main"> <div className="mutate"> <h1>Mutate Flow Blockchain</h1> <form onSubmit={(event) => { event.preventDefault(); saveCollectible(); }} > <input type="text" placeholder="enter name of the NFT" ref={nameInputRef} /> <input type="text" placeholder="enter a url" ref={urlInputRef} /> <button type="submit">Mint</button> </form> <mark>Your Collection will be initialized while minting NFT.</mark> </div> <div className="query"> <h1>Query Flow Blockchain</h1> <mark>Click below button to check 👇</mark> <button onClick={checkCollectionInit}>Check Collection</button> <p> Is your collection initialized: {isInitialized ? "Yes" : "No"} </p> <button onClick={viewIds}> View NFT IDs you hold in your collection </button> <p>NFT Id: </p> {ids.map((id) => ( <p key={id}>{id}</p> ))} </div> <div className="view"> <h1>View Your NFT</h1> <input type="text" placeholder="enter your NFT ID" onChange={handleInputChange} /> <button onClick={viewNFT}>View NFT</button> <div className="nft-card"> <p>NFT id: {nft.id}</p> <p>NFT name: {nft.name}</p> <img src={nft.image} alt={nft.name} /> </div> </div> </div> ) : ( <div className="main-2"> <h1>Connect Wallet to mint NFT!!</h1> </div> )} </div> );
最終的なコードをここで確認してください。
アプリが完成したので、使い方を見ていきましょう。
まず、右上の「ウォレットを接続」ボタンをクリックしてウォレットを接続します。
これでNFTを鋳造できるようになりました! NFT の名前を入力し、使用する画像へのリンクを貼り付けます。 「ミント」をクリックすると、ウォレットでのトランザクションに署名するよう求められます。
トランザクションが完了するまでに少し時間がかかる場合があります。完了したら、下のボタンをクリックして NFT の ID を表示できるようになります。初めての場合は、ID は「1」だけにしてください。
これで、NFT の ID をコピーし、[表示] セクションに貼り付けて、[NFT を表示] をクリックできます。
よくやった! Collectibles ポータル プロジェクトのパート 2 が完了しました。要約すると、私たちは Collectibles ポータルのフロントエンドの構築に重点を置きました。
これは次のようにして行いました。
本当に素晴らしい一日をお過ごしください!