paint-brush
So erstellen Sie ein digitales Sammlerportal mit Flow und Cadence (Teil 2)by@johnjvester
213

So erstellen Sie ein digitales Sammlerportal mit Flow und Cadence (Teil 2)

John Vester15m2024/02/27
Read on Terminal Reader

Mit einem Collectibles-Portal auf der Flow-Blockchain und der Bereitstellung im Testnetz können wir uns nun am Ende dieser Serie auf die Erstellung des Frontends mit React konzentrieren.
featured image - So erstellen Sie ein digitales Sammlerportal mit Flow und Cadence (Teil 2)
John Vester HackerNoon profile picture
0-item


Willkommen beim letzten Schritt bei der Erstellung Ihres Sammlerportals! (Teil 1 finden Sie hier )


In diesem Teil konzentrieren wir uns auf den Aufbau des Frontends – dem letzten Teil des Puzzles.


Folgendes werden wir erreichen:


  1. Verbinden Sie das Flow Wallet.
  2. Initialisieren Sie Ihr Konto und prägen Sie Ihr NFT.
  3. Überprüfen Sie die NFT-ID in Ihrer Sammlung.
  4. Sehen Sie sich den NFT mit der NFT-ID an, die Sie in Ihrer Sammlung haben.


Wir werden Next.js verwenden, um das Frontend zu erstellen.


Lass uns anfangen!


1. Installation

Einrichten

Öffnen Sie Ihr Projekt flow-collectible-portal Verzeichnis. Dann renne
npx create-next-app@latest frontend im Terminal und drücken Sie enter .


Dadurch stehen Ihnen mehrere Optionen zur Verfügung. In diesem Tutorial verwenden wir nicht Typescript , ESLint oder TailwindCSS und verwenden das src Verzeichnis und den App-Router zum Zeitpunkt dieses Artikels.


Jetzt haben Sie eine neue Web-App parat.

So sieht Ihr Frontend-Ordner aus:



2. Konfiguration

Um mit der Flow-Blockchain zu interagieren, verwenden wir die Flow Client Library (FCL), um Wallet-Verbindungen zu verwalten, Skripte auszuführen und Transaktionen in unserer Anwendung zu senden. Damit können wir komplette Cadence-Funktionen schreiben und sie als Javascript-Funktionen ausführen.


Um zu beginnen, installieren wir FCL für unsere App, indem wir den folgenden Befehl ausführen:


 npm install @onflow/fcl --save


Nach der Installation von FCL müssen wir es konfigurieren. Folgendes müssen Sie tun:


  1. Erstellen Sie im app Ordner einen neuen Ordner mit dem Namen flow und fügen Sie eine Datei mit dem Namen config.js hinzu.
  2. Richten Sie in dieser Datei die Konfiguration für die FCL ein, z. B. die Angabe des Zugriffsknotens und des Wallet-Erkennungsendpunkts. Dies hilft Ihnen bei der Wahl zwischen der Verwendung eines Testnetzes oder eines lokalen Emulators.
  3. Sie möchten auch die Vertragsadresse für Sammlerstücke angeben, die wir in Teil 1 bereitgestellt haben.


Fügen Sie der Datei config.js den folgenden Code hinzu:


 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", });


Jetzt sind Sie bereit, die FCL in Ihrer App zu verwenden.


3. Authentifizierung

Um die Identität eines Benutzers in einer App zu überprüfen, können Sie mehrere Funktionen verwenden:


  1. Rufen Sie zum Anmelden fcl.logIn() auf.
  2. Rufen Sie zum Anmelden fcl.signUp() auf.
  3. Rufen Sie zum Abmelden fcl.unauthenticate() auf.


Erfahren Sie, wie wir diese fcl Funktionen in Ihrem Frontend implementieren können.


Zuerst fügen wir den folgenden Code zu unserer page.js Datei im App-Verzeichnis hinzu. Dadurch werden einige Abhängigkeiten importiert, ein anfänglicher useState für Teile unserer App eingerichtet und eine grundlegende Benutzeroberfläche erstellt.


Um sicherzustellen, dass es gut aussieht, löschen Sie die Datei page.module.css im App-Verzeichnis und erstellen Sie stattdessen eine Datei mit dem Namen page.css. Fügen Sie dann den Inhalt dieser Datei ein. Jetzt können wir unsere erste Seite schreiben.


 "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> ); }


Nachdem Sie diesen Code hinzugefügt haben, führen Sie npm run dev aus, um sicherzustellen, dass alles korrekt geladen wird.


4. Abfrage der Flow-Blockchain

Bevor wir uns eingehend damit befassen, wie wir fcl zum Abfragen der Flow-Blockchain verwenden können, fügen Sie diese Cadence-Skriptcodes nach der handleInput Funktion in der Datei page.js hinzu.


 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) }


Da unsere Cadence-Skripte einsatzbereit sind, können wir nun einige Javascript-Funktionen deklarieren und die Cadence-Konstanten in die `fcl` -Abfragen übergeben.


 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); }


Schauen wir uns nun alle Funktionen an, die wir geschrieben haben. Dabei sind zwei Dinge zu beachten:


  1. Die fcl.query
  2. Und die args: (arg,t) => [arg(addr,t.Address)], Zeile.


Da Skripte den view in Solidity ähneln und für die Ausführung keine Gasgebühren anfallen, fragen wir im Wesentlichen nur die Blockchain ab. Deshalb verwenden wir fcl.query um Skripte auf Flow auszuführen.


Um etwas abzufragen, müssen wir ein Argument übergeben. Dazu verwenden wir arg, eine Funktion, die einen String-Wert annimmt, der das Argument darstellt, und t , ein Objekt, das alle verschiedenen Datentypen enthält, die Cadence hat. So können wir arg mitteilen, wie das von uns übergebene Argument kodiert und dekodiert werden soll.

5. Mutation der Flow-Blockchain

Während unsere vorherigen Funktionen nur „schreibgeschützt“ waren, werden unsere nächsten Aktionen haben, die den Blockchain-Status ändern und in ihn schreiben können; auch bekannt als „Mint an NFT“.


Dazu schreiben wir ein weiteres Cadence-Skript als Konstante.


 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) } }


Fügen Sie nun die folgende Funktion nach dem Transaktionscode zur Datei page.js hinzu.


 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); }


Was die Funktion betrifft, ist die Syntax fcl.mutate dieselbe wie die fcl.query . Wir stellen jedoch mehrere zusätzliche Parameter zur Verfügung, wie zum Beispiel die folgenden:


 payer: fcl.authz, proposer: fcl.authz, authorizations: [fcl.authz], limit: 50,


  • Dies sind Flow-spezifische Dinge, die definieren, welches Konto für die Transaktion bezahlt (Zahler), die Transaktion sendet (Antragsteller) und die Konten, von denen wir Autorisierungen benötigen. (Falls einem Konto mehrere Schlüssel zugeordnet sind, kann es sich wie eine Brieftasche mit mehreren Signaturen verhalten.)
  • fcl.authz bezieht sich auf das aktuell verbundene Konto.
  • limit ist wie gasLimit in der Ethereum-Welt, das eine Obergrenze für den maximalen Rechenaufwand festlegt. Wenn die Berechnung den Grenzwert überschreitet, schlägt die Transaktion fehl.


Wir müssen eine weitere Funktion hinzufügen, die die gerade erstellte mintNFT -Funktion aufruft und verarbeitet.


 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.'); } };


6. Endgültiger Code

Nachdem wir unsere Hauptfunktionen eingerichtet haben, können wir sie nun in unsere Benutzeroberfläche integrieren.


Bevor wir das tun, fügen wir jedoch einige useEffect Aufrufe hinzu, um das Laden des Anfangszustands zu erleichtern. Sie können diese direkt über dem bereits vorhandenen useEffect Aufruf hinzufügen.


 useEffect(() => { checkCollectionInit(); viewNFT(); }, [currentUser]); useEffect(() => { if (currentUser.loggedIn) { setCollectiblesList(collectiblesList); console.log('Setting collectibles...'); } }, [currentUser]);


Zurück in unserem return mit der Benutzeroberfläche können wir unsere Funktionen den entsprechenden Teilen der App hinzufügen.


 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> );


Überprüfen Sie den endgültigen Code hier .


Jetzt, da die App fertig ist, gehen wir durch die Bedienung!


Verbinden Sie zunächst Ihr Wallet, indem Sie oben rechts auf die Schaltfläche „Wallet verbinden“ klicken.


Jetzt können Sie einen NFT prägen! Geben Sie den Namen Ihres NFT ein und fügen Sie einen Link zu dem Bild ein, das Sie verwenden möchten. Nachdem Sie auf „Mint“ geklickt haben, werden Sie aufgefordert, eine Transaktion mit Ihrem Wallet zu unterzeichnen.


Es kann eine Weile dauern, bis die Transaktion abgeschlossen ist. Nach Abschluss des Vorgangs sollten Sie auf die untere Schaltfläche klicken können, um die IDs Ihrer NFTs anzuzeigen. Wenn dies Ihr erster ist, sollte die ID nur „1“ sein.


Jetzt können Sie die ID Ihres NFT kopieren, in den Abschnitt „Ansicht“ einfügen und auf „NFT anzeigen“ klicken.


Abschluss

Gut gemacht! Sie haben Teil 2 des Collectibles-Portalprojekts abgeschlossen. Zusammenfassend haben wir uns auf den Aufbau des Frontends unseres Sammlerportals konzentriert.


Wir haben dies getan, indem wir:


  • Erstellen einer App mit Next.js
  • Anschließen des Flow Wallets
  • Erstellen unserer eigenen NFTs zum Prägen
  • Anzeigen Ihres NFT


Ich wünsche Ihnen einen wirklich tollen Tag!