Now in the previous lesson, we created our NFT actor class and we saw that we were able to mint brand 1
new NFTs simply by passing in data for the name, the owner and the actual image data to this canister. 2
But of course, when we called these methods on the command line and when we got the results back, 3
the name and the owner are easy enough to read. 4
But the actual image, unless we're some sort of human computer, this is completely not understandable. 5
Let's try and get this to render on our frontend and to be displayed on our website. 6
So far we haven't really activated our frontend; we haven't actually seen what it looks like first. 7
Let's go ahead and do that. 8
We need to run our npm server. 9
So let's go ahead and do npm start. 10
And once that's up, we should be able to head over to localhost 8080 11
and it should show us our homepage. 12
So here we've got a header, we've got a footer, and we've got this image as our main homepage background 13
with all of the crypto dunks that I've created for you for this project. 14
If we go ahead and click on anything on the website, nothing is working right now. 15
So what we want to do, first of all, is to replace this home image with the image that we actually 16
uploaded when we used the command line code in our read me to deploy and mint this NFT. 17
So we want to see what this image actually looks like. 18
So to do that, we're going to head into our app component and we're going to comment out our home image 19
and replace it with the item component. 20
And as you type, it should start auto-suggesting this item component. 21
And if you select it and hit enter, it will automatically add the imports for you, which will save 22
you a little bit of headache and a little bit of potential for spelling mistakes. 23
Once we've done that, then we're going to head over into our item component and just quickly take a 24
look at it. 25
And I've kept the HTML relatively simple. 26
It's just going to display the image, the name and the owner. 27
And all of this is formatted in a cardlike structure. 28
So if we hit save and go over to our local host and hit refresh, you should be able to see it rendered 29
onscreen. 30
Now, don't worry about the layout and the centering. 31
We're going to deal with that a little bit later on. 32
But right now, what we're interested in is to replace these pieces of hardcoded data, including the 33
image which currently is just pulling our logo to the actual image and name and owner that we passed 34
in when we created and minted our NFT, 35
so all of this. In order to do that, we're going to pass in the ID of our canister as a prop to 36
this component. 37
If you go ahead and split off another terminal and run dfx canister ID and then the name of our canister, 38
which is called nft, then it will output the ID of our canister. 39
Once we've done that, let's go ahead and copy it and we're going to paste it into our app component. 40
So here I'm going to create a new constant which I'll call the NFTID. and I'm going to set it as 41
that string that I just copied from the command line. 42
Now I'm going to pass that in as the prop. 43
So I'm going to call this simply just the id and then I'm going to pass in this NFID as the prop. 44
That means over here in our item, we can tap into our props and we can get hold of our id by simply 45
calling props.id. 46
Now, we're going to use that a little bit later on in order to access that canister and to call the 47
methods on that canister, including getName, getOwner and getAsset. 48
But in order to be able to access that canister, we have to run a HTTP command to use hypertext transfer 49
protocol to fetch that canister on the Internet computer, blockchain. 50
In terms of working locally, that will be our local dfx. 51
So let's set this up by creating a new const which I'll call localHost, and I'm going to set 52
this up as the URL of our local host. 53
So I'll just copy and paste it in here. And then we're going to create a new HTTP agent, so we'll just 54
call it agent. 55
And this comes from an agent package that we installed when we initialized our project. 56
So this comes from Dfinity and it's there to help us run HTTP requests in order to get hold of canisters. 57
So the class is called HttpAgent and it's a capital H and lowercase ttp and then it's Agent. 58
And in order to use this, we, of course, have to import. The import statement... 59
be really careful not to make any typos because it's really, really easy. 60
Just take a look at what I'm writing. 61
It's again, capital H capital A; HttpAgent and from is going to be from @dfinity. 62
Again, another big potential for error. 63
So it's d-f-i-n-i-t y and then 64
/agent. 65
Now we can use that to create a new agent. 66
So the syntax is const agent = new HttpAgent. 67
And then we have to provide some initializes in the form of a JavaScript object. 68
And this is where we're going to pass our localhost that we constructed earlier on as the host property. 69
Basically, we're going to create a new HTTP agent which is going to make requests 70
and it's going to use the localhost. 71
Now the next thing we're going to do is to use this agent to fetch our nameOwner image. In order to 72
call the methods on our canister because they all return asynchronously, 73
that means we have to make these method calls inside an async function as well. 74
So I'm going to create a new async function, which I'm going to call loadNFT. 75
And inside this method, I'm going to use the agent to get hold of our NFT canister, which if you remember 76
is called an actor. 77
So let's create a const called NFTActor and this is going to be created through using an await 78
and the actor class from the dfinity agent. 79
So it's await Actor 80
.createActor. 81
And inside here we have to pass in two inputs. 82
The first input is going to be an idl factory. 83
So the idl factory lives inside the declarations folder. And we want to pass over the idl factory 84
for our NFT canister. 85
If you take a look inside nft.did.js, you can see that here 86
the idlFactory is being created and exported. 87
And what it basically does is it gives our frontend a translated version of our Motoko backend so that 88
our JavaScript will know which method can be called in our NFT canister. 89
There's getAsset, getName and getOwner. And also what inputs are expected and what outputs will be 90
returned. 91
It's basically like a translator between our Motoko code and our JavaScript code. 92
We need to import this idlFactory and pass it in when we create our actor. 93
We're going to say import 94
idlFactory 95
from... 96
And then we have to go up a few steps... 97
so ../ and then go to declarations and then go to the NFT declarations like 98
so. 99
And let's just check to make sure that we haven't made any typos. 100
It is in capital F, but lowercase idl. 101
Okay. 102
So now that we've got that, let's go ahead and create our actor by passing in that idlFactory. 103
And then the second input here will be any options, 104
so the agentOptions and the actorOptions. We're going to pass in the agent as the agent that we constructed 105
up here, our new HttpAgent, and then we're going to pass in our canister ID 106
as the one that we got from our props. 107
So we got it right here. Now because this is a piece of plain text, as you can see here, that's just 108
was passed over, 109
we have to turn this into an actual principal type. 110
So we've done this plenty of times before. 111
We have to first import the principal type from the dfinity module that we installed, and then we 112
use the principal.fromText method and wrap our props.id into that method. 113
And if there are no typos, then we should be able to pass that in as our canisterID. 114
So now is a question of when do we actually load our NFT? 115
When do we want to call this method? 116
Well, if you think about it, we only really want to call this once, and that's the first time this 117
item component gets rendered. 118
So that should ring some bells. 119
And the reason why I say that is because we've used this before. 120
We want to use the useEffect hook to pass in a JavaScript fat arrow function. 121
That's all it is, 122
right? 123
So inputs, fat arrow and then the body. 124
And then we want to add a comma after that first input, and add our second input, which is going to 125
be a empty array because this is what's monitored to see how many times the function in useEffect should 126
be called. 127
And if we leave it empty, then that means it's only going to be called the first time this component 128
gets rendered. 129
So now let's think about what to put inside this function. 130
And in our case, it's going to be to call the loadNFT method that we created right here. 131
Now that we've got pretty much all the setup done, the next step is to actually grab hold of the pieces 132
of data that we want from this NFT canister. 133
If we go ahead and say NFTActor., then we can call any of the methods that's inside this NFTActor. 134
So we can call, getName, getOwner and getAsset. 135
So I'm going to start from the top. 136
I'm going to call the getName method. 137
And remember because this is asynchronous, we have to use the await keyword in front of it. 138
And then I'm going to save it inside a const called name. 139
Once this name comes back, I want to use it to update my HTML so that instead of this hard-coded text 140
here, I want to be able to pass it in as a React state variable. 141
So I'm going to call it the name and it's crossed out because it doesn't exist right now. 142
So let's go ahead and create it. 143
And we're going to be using our use hooks that you've seen plenty of times now. 144
So it's going to be name and setName and it's going to useState. 145
And if we select it and hit enter, then it will automatically import it to this line here. 146
And we're going to say that the starting state will just be nothing. 147
It'll be undefined. 148
Once we've got this from NFTActor.getName, then let's go ahead and call setName and pass i 149
the result of this method call. 150
Now let's go ahead and hit save and take a look at our front-end and you should find that our name has 151
now been replaced from the previous, which I think was 321, to now 123, 152
which comes from that line in our read me when we initialized this new crypto dunk. 153
Now I want you to go ahead and try to do the same thing for the user ID. 154
Remember though, that in order for it to go in here, it should be in text format. 155
Whereas what you will receive from the NFT canister will be the principal format. 156
So just keep in mind that fact while you complete this challenge. 157
So try to do everything that we did for the name of the NFT, 158
but do it this time for the owner. 159
Pause the video and try to make this owner update to the actual owner ID of the NFT. 160
All right. 161
As we did before, we're going to create a new const which I'll call owner, and then we're going 162
to use await to call on our NFTActor and call the method getOwner. 163
At least I think that's what it's called. 164
Let's just make sure that we didn't make any typos here because the IDE tooling for Motoko is not that great. 165
It's not going to auto-suggest it or auto-fill it for us. 166
But once we got hold of that, we're going to call on a method that doesn't exist yet called setOwner 167
and pass in the owner. So it doesn't exist because we haven't created it. 168
I'm going to create it right here. 169
So owner and setOwner. 170
And again, I'm going to start off with an undefined state. 171
So now let's replace this part with what's inside our owner. 172
And as I said, remember that this will come back as a principal data type. 173
So in order to get it into an actual text format when we want to set it, what you have to do is to 174
use the method toText, which comes from that principal input. 175
And we've done this before. 176
So you should have seen this already. 177
But it's going to convert that principal data type into a text data type, which can then be used 178
by JavaScript to insert in here. 179
So let's hit save and let's check it out. 180
And if yours is as long as mine, then it probably means that you've got it set up correctly. 181
Now, the last thing we have to update is the image, which is a little bit tricky. 182
So we're going to do it together. 183
And in order to get the image to display, we have to convert that imageBytes, which currently is in 184
a format of an array of eight-bit numbers, into something that can be read as a URL by our image element 185
here. 186
So we have to set the source here. 187
The first thing we're going to do is we're going to create a new constant, which I'm going to call 188
imageData. 189
And this is going to come from our await NFTActor.getAsset 190
And that's going to call this method here, returning to us this array of eight-bit numbers. 191
And in order to get that to be recognizable by JavaScript, we have to convert it into what's called 192
a UInt8Array. 193
We can do that through using the new UInt8Array, and I'm not going to type it. 194
I'm just going to hit enter and get to auto-insert just to make sure I don't make any typos there. 195
And I'm going to pass in our image data that we got back from our back end in order to convert it into 196
this format that can be read by JavaScript. 197
So save that into another constant, which I'll call imageContent. 198
And finally, we're going to turn that imageContent into an actual URL. 199
So let's create a new const which I'll call image, and we're going to use the URL.createObject 200
URL in order to convert our imageContent into an actual object URL that can be used on the frontend. 201
This is going to be URL.createObjectURL and we're going to pass in our imageContent as 202
a blob data type. 203
The blob objects are this kind of really easy data type that can be converted from many different 204
formats. 205
We're actually converting an array of Nat eight numbers from our back end that's stored on the internet 206
computer blockchain into something that can be read by JavaScript. 207
Now here we need to create a new blob. 208
The syntax for creating a blob is to simply pass in an array, and optionally you can pass in some options, 209
such as the the data type that's stored in the blob. 210
And there are some examples on how to create a blob on the Mozilla developer docs. 211
So let's go ahead and try to use this format to create our blob. 212
So we're going to say new blob and then we're going to pass in an array, so open up some square brackets. 213
We're going to pass another imageContent and we're going to use .buffer to turn it into a array 214
buffer. 215
And then we're going to pass in some options. 216
We're going to open up some curly braces and use the type key to specify that these are going to be 217
image/png. 218
So now let's hit save and let's go ahead and set our image. 219
So setImage to image and let's add that up here. 220
So const image setImage = useState. 221
And again, setting it to empty. 222
And now down here in our image HTML, we'll replace our logo with that image that we created. 223
So let's hit save and let's go over to our OpenD and you can see here is our entire NFT item and for the 224
first time you can actually visualize the NFT as an image. 225
That's pretty cool. 226
We've got our name, we've got our owner, and we've got the image displayed on screen. 227
So now that we've seen how we can mint an NFT and display our NFT, the next step is to be able to allow 228
our users to mint their NFTs by uploading an image to our OpenD website. 229
So for all of that and more, I'll see you on the next lesson.