We completed a transaction in the last part, but the transaction data had yet to be seen. In this part, we will drive the smart contract data to the user interface. The user’s data and the transaction time will be displayed on the user interface.
This is part 4 of our four-tutorial series on creating a decentralized web app to sell ebooks: π
- Part 1: I Created a React Decentralized App to Sell eBooks – Here’s How (1/4)
- Part 2: I Created a React Decentralized App to Sell eBooks – Here’s How (2/4)
- Part 3: I Created a React Decentralized App to Sell eBooks – Here’s How (3/4)
- Part 4: I Created a React Decentralized App to Sell eBooks – Here’s How (4/4)
Move to the Receipt
component and import the ethers
library. Set the state that we created on the app.js
file as props. Here again, we need to connect the smart contract with the frontend. So, destruct the contract from the state.
const Receipts = ({ state }) => { const { contract } = state; const [receipts, setReceipts] = useState([]); useEffect(() => { const receiptsInfo = async () => { const contractReceipts = await contract.getReceipts(); setReceipts(contractReceipts); }; contract && receiptsInfo(); }, [contract]); return ( <> </> ); }; export default Receipts;
Again we used the useEffect()
hook of the react to write all our codes inside.
Inside the useEffect()
hook, we created an async receiptsInfo()
function to collect the information on the receipts. It is also an async await
function.
You must remember we have created a receipts array in the smart contract to store all the transaction receipts together. At the same time, we also created a getReceipts()
function inside the contract to fetch all the information regarding the transaction. Here, we created a receipts constant and called the getReceipts
method from the contract instance.
To show the receipts info on the user interface, we created a receipts state variable with the help of useState
hook. At last, we have set the receipts as the receipts we got from the contract.
We need to initiate the function. Otherwise, the code will not work. I initiated the contract and the receiptsInfo()
function at the same time.
Ultimately, we add the contract as a dependency of the useEffect()
hook. That means every time you bring some changes to the contract, the page will render again.
Display Data on the Browser
Now we have all the receipts in our hands. To show these receipts, we will map through the receipts and display them in a table format.
We need a table with five columns, so visit the flow bite website again. Why do you waste time doing the front end? If you like, you can use your CSS code, also. But for the fast demonstration, those ready-to-use codes are my favorites.
Now create a <h1>
tag inside the return function for a heading that will remain on top of the table. βRecent Subscribersβ is a good heading, I think.
return ( <div className="py-10"> <h1 className="text-center text-2xl font-extrabold font-serif text-cyan-700"> RECENT SUBSCRIBERS </h1> <div className="relative overflow-x-auto shadow-md sm:rounded-lg w-3/4 m-auto mt-1"> <table className="w-full text-sm text-left text-gray-500 dark:text-gray-400"> <thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400"> <tr> <th scope="col" className="px-6 py-3"> BUYER </th> <th scope="col" className="px-6 py-3"> BOOK </th> <th scope="col" className="px-6 py-3"> WRITER </th> <th scope="col" className="px-6 py-3"> ADDRESS </th> <th scope="col" className="px-6 py-3"> TIME </th> </tr> </thead> {receipts.map((receipt) => { return ( <tbody> <tr className="bg-white border-b dark:bg-gray-900 dark:border-gray-700"> <td className="px-6 py-4">{receipt.name}</td> <td className="px-6 py-4">{receipt.book}</td> <td className="px-6 py-4">{receipt.writer}</td> <td className="px-6 py-4">{receipt.buyer}</td> <td className="px-6 py-4">{String(receipt.timestamp)}</td> </tr> </tbody> ); })} </table> </div> </div> ); };
Create a new <div>
then. Inside the <div>
, pass the code of the table structure that we copied from the flowbite website.
From the table structure, just keep a row of the table data and delete others. We will pass dynamic content on the table structure. So, the rows will be generated automatically.
If we start mapping through the receipt, the table header will be repeated with the dynamic code. So, we should map the receipts from where the table header is finished. But first, change the captions of the columns.
I changed the five columns’ captions to buyer, book, writer, address, and time.
Now we can map through the receipts array. We will only map through the table body and insert each buyer’s info in each row.
- By mapping through the array, we are iterating over the receipts. Apart from this, we are getting the info on each receipt simultaneously.
- We can access each receipt’s data now, and from the receipt, we can collect dynamic data like
receipt.name
,receipt.book
,receipt.writer
,receipt.buyer
andreceipt.timestamp
. In the Solidity smart contract, we created a struct for all those data. Now we are fetching the input data, the buyer’s account address, and the transaction timing from the contract. - Now insert these dynamic data on each of the table data tag (
<td>
) of the table row. When a new buyer subscribes, automatically, a new row for this buyer will be created on display. - The
recipt.timestamp
will return an object. To get the readable format convert it into a string.
Send Ethers from Buyer to Owner
Now our dapp is ready. But for a long time, we have been using the same account for receiving and sending ethers.
Now let’s create a different account on the Goerli test net. You can easily do this from the Metamask wallet. Just move to “my accounts” section, and you will find create a new account option. Create a new account there. Then send some Goerli eth on your empty account from the Goerli faucet.
Assume that the second account is the buyer, who will buy a subscription now.
The first address is obviously the bookstall owner, as we deployed the contract from the first address. Connect the second account with the browser. You can do this manually from the wallet. Now input the required information in the form and hit subscribe button. When the Metamask appears, confirm the transaction.
If your dapp is active, you should see the transaction confirmation notification after some time. You can check the transaction status on the Etherscan website by clicking on that notification. You will see the transaction details, including the receiver and sender addresses, from there.
My transaction details are here for you. You can see the amount that has been transferred along with the transaction fee. The sender and receiver addresses and the contract address are mentioned there.
You can confirm the transaction in another way. Just check the Metamask wallet of the buyer and the owner. You must see that the owner’s account is credited with 0.001 eth. The buyer’s account must be debited with the subscription and transaction fees. All the buyers will bear the cost of the transaction.
If you reload the browser, the last buyer’s data should be added to the table in a new row. Our bookstall project is accomplished if you get the correct data in the user interface.
You can check the video for the live demonstration of the transaction. I beautified the front end a little with the help of Tailwind CSS, and you can get the code from the GitHub link attached below.
Thanks! β₯οΈ
That was all for my bookstall dapp. You are always appreciated for creating new dapp by taking the ideal concept out of this. Thanks for reading.
GitHub: https://github.com/finxter/bookSell
Also, check out our academy courses on smart contract development such as this one: