All right. 1
So in the last lesson, we saw that we were able to get the balance by querying our HashMap, and we're 2
able to return the result from this public query function. 3
And we test that on the command line using our own OWNER_PUBLIC_KEY. 4
Now, we want to be able to get this to work using the front-end instead of using the command line. 5
So to do that, we have to write some code in the balance.jsx. 6
Now in this file, I've already got the HTML pretty much done for you because that part is easy. 7
But we're going to be writing the JavaScript code in order to hook it up with our backend and get it 8
to work. 9
So the first thing we want to do is notice that we've got this handleClick listener hooked up so that 10
whenever the user clicks on this button, request balance, then it will trigger this function. 11
And inside this function, currently we've just got a console log. 12
So if we go ahead and test it on the front-end, so if we go ahead and click Check Balance, then you 13
can see it triggers this function call. 14
So instead of doing a console.log, what we want to do instead is we want to use await and call our function, 15
which is balanceOf. And we want to pass in the principal that the user typed inside that text field 16
right here. 17
So that's an input which is right here. 18
And in order get hold of what's inside the input, we have to add a value attribute. 19
Now the value is going to be an input value, 20
so whatever the user types in there. And we're going to capture that inside a constant. 21
So we're going to create a cons which is using the React use state. 22
So we're going to set the const to be called inputValue, just like what we've got down here. 23
And we're going to give it also a setter as well, 24
so setInput. And this is going to be tracked using our useState hook and we're going to set the initial 25
value to just an empty string. 26
We've got our useState which is from our React module and in order to set the input value, we have 27
to add an onChange listener attribute as well so that when it changes, we will trigger a function 28
which in this case is just going to be using the JavaScript fat arrow and we're going to call setInput 29
to set it to the e.target.value. 30
What this is going to do is whenever this input gets changed, which means that the user's typing something 31
into it, it's going to trigger this function. 32
And this function takes the event that caused the trigger and it calls our setInput setter method in 33
order to set the input values state to the event that triggered it, 34
so the typing .target, which is going to be this current input element, .value, which is going 35
to be whatever the user typed in here. 36
And this kind of format is really commonly seen in React where we have an input, the value is set using 37
the constant and when it's on change, trigger the setter for that constant. 38
Let's just make sure that actually works so that we actually console.log. Instead of balance button clicked, 39
we're going to console.log input value and let's go ahead and hit save and go back to our front-end. 40
And I'm just going to type something in here, click check balance, and you can see that it's got a hold 41
of the input inside that field. 42
So brilliant. 43
Now the next thing we want to do is we want to take that input value and pass it back into here. 44
But we don't want to pass it back just as text, which is what we've got currently, 45
whatever we type into the input field is going to be served up as text. But instead, we want to convert 46
it into a principal data type and then call this function passing that in as the input. In order to 47
import the classes from Motoko on the front-end 48
in JavaScript, our import will look a little bit different. 49
So we're going to import the principal type and it's going to come from our dfinity module. 50
So it's going to be @dfinity/principal. 51
This is really similar to our Motoko mo:base/Principal, but this is written obviously in JavaScript, 52
but also this comes from our package.json @dfinity. 53
This is where it's getting it from. 54
And the @ sign basically just denotes a scoped package, which is sort of a way of grouping similar 55
packages together 56
instead of having them all separate. We can get hold of the Dfinity principal type by using this import, 57
and then we can create our principal by converting it using the Principal type. 58
So we're going to say Principal.fromText. 59
We did this in our main.mo when we got hold of our owner's principal from the command line and 60
then we converted it into an actual Principal type using that method. 61
But in this case, we're converting it from the current input value. 62
So we're basically taking whatever the user types inside here and then converting it into a Principal 63
type, 64
and then finally, we're going to call that method, balanceOf, from our main.mo. Again, 65
in order to be able to call the methods in our back end, we have to import it. 66
So we're going to import our actor, which is our token canister, and we're going to get it from our 67
relative path. 68
So I actually need three of these .. slashes and then we go into the declarations folder which is right here, 69
and then from there we can access the token bridge file. 70
This is what it should look like to import. 71
Now I can say await token.balanceOf. 72
And this method requires a principal to be passed in, which is what we have created in the previous 73
line here. 74
And then we're going to set this to a const which I'm going to call balance. 75
And we want to display that balance inside this paragraph element here. 76
Now, instead of having XYZ, we're going to display the balance result here. 77
And for that to work, we need to create another constant that has state. 78
So we called it balanceResult. 79
And we're going to have a setter which is going to be called setBalance. 80
So we're going to useState and we're going to set the balance to have an initial value of also just 81
an empty string. 82
So notice that this is actually going to be a string or a text data type. 83
When we get this balance back, it's going to look like this. 84
It's going to be formatted like this, and it's going to be a natural number. In order to set it properly, 85
so using our setBalance, we want to change this into a string. 86
And JavaScript rather handily actually has a method which is called toLocaleString. And make sure that 87
you've got the correct spelling. 88
It's not local, it's locale. 89
And then at the end we add a set of parentheses to actually convert this number into a formatted number, 90
which is going to be a string. 91
And if we hit save and go back to our front-end, if we paste in that principal ID, click check balance, 92
then you can see it shows up right here. 93
Perfect. 94
That actually worked using our back-end. 95
And that is how we can get our front-end to pull in the data from our back-end and to format it to be 96
able to see it on the website. 97
Now, there's a couple of things that we want to fix here. 98
Firstly, it would be nice if we can also get hold of our currency so that it could say 1 billion DANG 99
or whatever your currency is called. 100
And I actually want to set that to you as a challenge. 101
Can you modify the Motoko code as well as the JavaScript code so that your currency symbol shows up 102
just after the balance? 103
I'll give you a few seconds to pause the video before I show you the solution. 104
Ready? 105
Here's the solution. 106
Let's go back into our main.mo and let's create another query function. 107
So public query func and we'll call this one getSymbol. 108
So it's not going to take any inputs, but it is going to return a text. 109
Let's add a semicolon there to make this error go away. 110
And we're just simply going to return whatever is the value of our symbol right here. 111
So whatever it is that you set right here is going to be returned to our method. So we can create a new 112
const which we'll call a cryptoSymbol and will have a setSymbol method as well. 113
And we're going to useState and set it to have an initial value of an empty string. 114
And here we're going to use a setSymbol and call our await token 115
.getSymbol 116
method, like this. 117
So let me just check that I've got the method correct. 118
It's called getSymbol, 119
I called getSymbol. 120
Perfect. 121
And then down here, just after our balanceResult, we're going to add in our cryptoSymbol to show 122
up. 123
Let's hit save. 124
Let's copy our principle ID and paste it. 125
Now, this is really important. 126
You can see that it says type error, token, blah, blah, blah is not a function. 127
Now, can you figure out why that is? 128
Because this will happen to you quite a few times when you're doing ICP development. 129
So the reason is because we updated on main.mo code and we updated our front-end. Whenever we 130
update our front-end, because we're using the automatic reload on our npm server using npm start, it 131
will automatically restart the server, but it will not automatically do dfx deploy for us. 132
And because we've changed the backend, our Motoko file, we have to do that in order to pull that into 133
our declarations and to actually be able to access it from our frontend. 134
So let's do that, 135
dfx deploy. 136
And once that's done, you can see we can now access this method. 137
And if we hit, save and go back, we should now be able to get it to show up. 138
So perfect. 139
The next thing I want to do is I want to hide this feedback message, because when you first load it 140
up and you don't have any accounts, it just says this account has a balance of . 141
It doesn't really make much sense. 142
So what we can do is we can create a new const called isHidden and we can setHidden as the setter. 143
And we're going to start off with a value of true. 144
And we can set the hidden attribute on our paragraph to be equal to the isHidden constant that we've 145
got up here and we want to set it to be not hidden 146
once we've gotten back the balance and the symbol and the user actually clicked on the button. 147
So we can say setHidden and we'll set it to false inside here. 148
Now let's go back 149
and you can see initially there's no text below the button. 150
But if we check our balance, then you can see that paragraph suddenly appears. 151
This is really just sort of improving the appearance and improving the UX of our frontend. 152
It doesn't really change the main functionality, which we've already achieved. 153
There you have it. 154
We've got our balance checking mechanism complete and we can now move on to the next aspect, which 155
is getting our faucet to run and being able to tap into the faucet and give any user 10,000 free tokens. 156
So for all of that and more, 157
I'll see you in the next lesson.