Full Stack React & Firebase Tutorial – Build a social media app

Hi. In this series, we're going to be learning
how to use react and Firebase to create a fully featured social media application. So
application will let us sign up by filling the signup form right here, which will be
validated once it's submitted. And if all the info is valid, an account will be created
for us and we will be redirected to the homepage. In the homepage, we can view posts, which
are called screams in this platform, we can see comments and the number of likes and scream
has, we can also upload an image that will be our profile picture that will be stored
in our Firebase Storage bucket. We can also update our profile by adding details about
ourselves such as a bio, our location, and our personal or professional website.

Once
these are submitted, they are validated. And once they're valid, these details will be
publicly visible to other users of the application. We can also always edit them again, if we're
not happy. We can like other people's screams, we can make as many screens as we want. We
can of course, post comments to screams. And they will be reflected immediately, as we
will see here. And we can of course post our own screens by pressing the plus button at
the top and type in stuff, as you see me here type very slowly, and pressing Submit.

And
once we submit a post, it will immediately show up on the application. And we can of
course like our own post, as absurd as you or I might think that is we can of course
post as many screens as we want. And if we make a mistake, we can also delete the screen,
we using the delete button will show us a screen, a confirm dial just to make sure that
we don't accidentally delete them, we can see other users pages and their posts. And
if we do log out right now. And if we do log in as the other user that we just liked and
commented to the screen, we will see a bunch of notifications informing us of exactly just
that.

And if we click on any notification, it will take us to that post that the notification
was talking about. As I mentioned, our app will use Firebase as a back end. And this
right here is the database. And we can see it update in real time as we add screens,
which is going to be super useful when we are developing our app, we can see our database
collections, things like screams, notifications and comments right here. And all the other
collections. We can also see information about our users and stuff like that.

We will also
be using Redux for managing our application wide state, which will hold the data needed
in our react application. This right here is the Redux dev tools, which will be super
useful later when we are developing our app, it will make it easier to see what's happening
in our application, what data we have, and what errors we have. And this will all be
you clear when we dive into Redux later. Before we start anything, I just want to give
a quick run through the tools that we're going to be using. Starting with the big one, the
front end library of choice that we're going to be using is react. React is a great framework
for building component based web applications.

Even though it's technically not frameworks,
the library, we will be complementing it with things like react router, Dom and axios, and
a couple of other libraries that will make it feel like a complete framework and will
allow us to do everything that we need to do. So yeah, it's a great library for building
components, building templates for our pages, and building dynamic markup for our for our
application pages.

Now, I do have a big disclaimer though. If you are not familiar with react
a an absolute newbie and have never touched react, this series is not for you. I recommend
that you learn the basics of react and get comfortable with it. And of course, be comfortable
writing JavaScript, and then come back to the series and then you will do some proper
learning. If you're familiar with react, then you're right at home. So next thing is Firebase.
Firebase is a great platform as a service, we will use it as our back end. It offers
us multiple services, of which we will use Cloud firestore as a database. It's a real
time database. And it gives us two access to a couple of really cool functionalities
to use a no SQL database document base, which we'll see later. Next thing is Cloud Functions
we're going to be we're not going to be writing like a Node JS.

Like server code. Even though
Cloud Functions are based on address, we will be writing a couple of functions that will
be run whenever we need to run them. Next thing is authentication. We're going to be
using Firebase authentication to register our users and log them in and get authentication
tokens and a bunch of other cool stuff. And we will also use their cloud storage service
to store our profile images that are submitted by our users. Next thing is material UI, which
is something that I've come to learn and really love recently. Material UI is one of the best
if not the best react implementation of Google material design standards. Think of Google
material design is like a CSS framework.

It's a couple of standards for designing user interfaces.
It's really cool. I really like material UI, they have amazing documentation, which makes
learning and implementing it really smooth sailing. Next thing is this might come as
a surprise to some of you, we're going to be using Express. I know we're not using Node
JS. But Cloud Functions are essentially no JS code that is executed on demand. So we
don't need to use Express, but it's better. I think, in my opinion, if we do because it
makes the code much cleaner. As you will see later, it will help us group our code and
separate our routes properly, and handle our requests and send our response properly in
writing our API. Last but not least, for sure, is Redux. So our application is going to have
a lot of components. And they're going to need to access data. And best practices when
you have a lot of components. And a lot of them need to access data is to not pass data
from one to the other, aka prop drilling, I will post a link to a really cool post that
explains why Redux is a thing and why people use it instead of just passing props around.
Redux makes it really seamless to have an application wide state that all the components
can separately talk to and fetch data and send data to if needed.

So yeah, we will of
course be diving deeper into the definitions and functionalities of each of these tools.
When we work with them separately, I just wanted to quickly show you what this series
is going to be using. So in this video, we're going to start to
work on our back end by creating some of the Cloud Functions that will give us access to
our database. And that will give users access to the Authentication Service, etc. So before
going to start, I'm going to go over some of the prerequisites that you need to work
on this project. So number one is no js, we need this just to use NPM for installing some
of the packages. Number two will be VS code. Now this is optional, but I recommend VS code
is the best text editor for me out there. Even atom and sublime are pretty good as well.
But some of the extensions of VS code are really, really, really good.

Number three
is postman. If you don't have it, download it, we're going to be using this to run an
API request to test our API, either Windows, Mac OS, or Linux, all download links are available.
I want to show you something on VS code, just so that we are on the same page, I will be
using bracket pair colorizer, which will color some of the brackets differently that will
make our code easier, easier to read. prettier, which formats the code each time I save, so
that we don't have to indent and yes seven, React Redux etc. snippets, which will give
us access to some of the snippets that would generate code without without us having to
type all of it. Okay, that's it with the prerequisites. So let's actually start creating our project.
So here, and firebase.google.com. Let's go to our console by clicking go to console.
And as our console loads, now we can create our project, click Add project. And let's
call this social ape. Because that's what we all are at the end of the day, I guess.
Select your region and country.

I'm in the UK. So I'm going to select United Kingdom,
select the server that is closest to you. To me, it's your request, and hit they accept
and create your project. This will now create a basic Firebase project with everything initialized.
Okay, now that it's done, click Continue. First thing I want to do, let's go to functions.
And once that loads, let's click get started, which gives us some instructions tells us
to install this package.

Let's click continue and finish. We'll do this separately. Okay.
Let's go to our desktop or whatever, really. And I'm going to use the basic command line
because it's interactive and not good bash. Here, let's install that package. So npm install
dash g Firebase dash tools, which will give us access to the Firebase command.

Line interface
that will let us create our functions and deploy them to our application. And I'll be
back once this is done installing. Okay, now that it's done installing, by the way, you
can just ignore this message thing. It's not important, we can run Firebase login, so that
we can authenticate today it would know who we are. And for me, it says, I'm already logged
in for you, maybe it will just pop up a browser window, and you just select your Google account.
So here, I'm going to go to my desktop. And I'm going to create a directory called social
Pape dash functions. Going to CD into that. And here, we're going to run Firebase and
knit for initialize, which will create our project, we want to proceed Yes, and hit space
on functions. And this is all that we're going to select for now as from services, and here
you choose from your projects, choose the project that we just created, it's going to
ask us to use JavaScript or TypeScript, we're going to use JavaScript and ies Linton, I'm
going to say no to this.

And let's say yes to installing packages, which will now install
all the dependencies that we need, I think, like two or three dependencies. So I'll be
back once this is done. Okay, now this, this is done. If you have Visual Studio code, you
can run the command code dot, which will open this in VS code. And there we go. So this
is what we get a get ignore file, and a Firebase config file that has our project ID, we go
to the folder functions to index dot j, s, this is where our functions will sit. And
as you can see if we uncomment this, this is a basic hello world function that comes
shipped with Firebase. Let's change this text to say, Hello world. And oops, hello, world. Let's open up the command line. And let's
run Firebase deploy. This will now deploy this function so that we can test it and see
if everything is working fine. Funny that our hello world function didn't actually have
hello world as the return. Okay, so now we will deploy our function to our, to our functions,
and it will give us an endpoint which we can call to see the response from that function.
And if you're, by any means familiar with node, this, the syntax of request response
and a callback should be familiar to you.

If not, we will work with a new you will get
familiar with it. Okay, so now that our function is deployed, we get an endpoint right here.
So let's copy this. And let's open up postman. And let's see if this is working. To wait
for postman to open. Let's put these side by side. So let's base this on. Let's hit
send. And indeed, it says hello world. So we're up and running. Okay, let's do something
a bit more complicated than that. Let's go to our project. We're here to close these
windows. Let's go to database and initialize our database. So we click CREATE DATABASE.
And it asks us whether to start in locked mode, or test mode, which these are like database
access rules that give us access to read or write some of the documents for now let's
go in test mode, which will leave all resources open for everyone to edit, which is crazy,
but we're not in production yet.

So it's fine. As well wait for it to set up everything.
Now we can actually start creating some documents in our database. Let's create the first collection
which will hold our posts which are screams if you remember, so screams is the collection
name. And let's actually create our first document. This will have a field called user
handle, which will determine which will let us determine which user submitted this last
type user. Now this user doesn't exist yet, but let's just roll with it for now. The body
of the scream should say first scream are under no.

And this will have a created add
field. This will be a timestamp. Let's give it the date of today. And it was posted at
midnight because why not? And now this will create our first screen. Let's actually create
another one quickly Here's a user handle again, it's the same user. And it's got the body
field, this should say, second scream. And let's add the created field as timestamp,
and give it the date of today.

Let's say this was created at 1am. So let's save. Now we
have a database with a collection of screams with two documents in it. Now, let's try to
whoops, yep, let's try to actually fetch these posts from the database. So let's create another
function. We'll call this exports dot get screams. And this will be from the functions
namespace. And from the HTTPS area, I guess. And we will use honor requests, we will use
some other handles some other functions later.

But for now, we'll stick with on request,
oops. So this will be will take a request and a response. And these are arguments so
we can name them however we want. And our function now needs access to the database,
we will be using something called the Admin SDK, we will import that by doing constant
admin, we already have the package installed, let's do require. As you notice, here, we're
not doing import from this is not your sixth because this is this is basically no JS code
to do require Firebase admin. And to use the admin, we need to initialize our application.
So we'll just do admin dot initialize app. And usually, we would pass an application
but this project already knows that this is our ID of our application. So we just do it
like this. And now we have access to the admin object, we can do admin dot firestore dot
collection.

And now we give it the name of the collection that we want to access. By
the way, all of this is in the documentation. If you want to see quickly, we can go to Firebase,
actually, we can just google just duplicate this thing, just google Firebase firestore.
And by the way, I really recommend checking out the Firebase documentation that really,
really comprehensive so if we go to fire, cloud firestore, and we go to read data, get
data once. And let me change this for readability. And I believe, yeah, it's right here. So to
get all documents in a collection, you run DB dot collection, which in this case is admin
Docker dot firestore. And you give the name of the collection, and you just run dot get,
which returns a promise, which holds a query snapshot. And in that query snapshot, we have
an array of documents, and I'll show you how we're going to fetch that fetch those. But
let's actually maximize this. So the collection is screams. And let's do dot get. And then
we do dot, then we have some data.

And if you hover over here, you see that this whoops,
this should not be any, you should give us a type. For some reason, it doesn't. Okay,
let's just go with it for now. So we say data. Yeah, now it does. So this is a query snapshot
type, which has a Doc's in it. So if you do data dot Doc's, you'll see it has a property
Doc's which has an array of documents, snapshots, which are documents, so we can do data dot
for each document. And we need to store them in something. So let's initialize an array
called screams, which is an empty and empty for now.

Here for each document, we want to
do screams dot push. And we don't just do Doc, because this is just a reference, we
do doc dot data, which is a function that returns the data that's inside the document.
And now this after this for loop, the screen should be populated with the data of the screams
that we have. Now we need to return them. So let's do return response dot JSON to return
it as a JSON object. And let's do screams. And let's put a colon and of course this returns
a promise it will be good practice to catch any errors that might happen.

So we do catch
error. And if any error happens, we just want to console. log it to the console using console
error. error. Like this. Now we hit save. And now we can do Firebase deploy again. And
this will deploy our function. And we can test if it's actually working. Okay, now that
our function is deployed, we can actually test it. So let's copy this endpoint. And
let's go to postman. Let's make this bigger. And let's paste our endpoint here, and hit
send. And this should bring up the documents that we just created. And it does. So this
is the first document. Rather, this is the second document, which says second screen.
And this is the first one which says first scream are perfect. So so this is for getting
documents, let's create another function for actually creating documents. So let's do exports
dot. Let's call this create, scream. And we can actually just copy this, like this, remove
the code inside of it. And here, we're going to get a request body because
this should be a POST request.

So let's initialize our screen, let's call this new screen. And
this will have a body of request, and our request will have a body. And don't get confused
this, this body is the body of the request. And we're going to do dot body, which is a
property in the body of the request. And this will make sense in a second. And the user
handle will be request dot body dot user handle. And we need a created art. So as to create
art equals I think this is admin, dot firestore dot timestamp timestamp that will use a function
called from date, which will create a timestamp from a normal JavaScript date object. So we
do new day, we'll pass it a new date. And now we have our object, we need to persist
it in our database. So let's do admin dot firestore dot collection. And same collection
screams. This time, we're going to use a function called add, which will take a JSON object
and add it to our database.

And the object in this case is our new scream object. And
this again, returns a promise. So we do thought then this will give us a document reference
as a response, which is actually which we're not going to do anything with this document
reference. So we need we can just do this, because we're not going to do anything. Actually
we are the scope that document reference.

Now, if we are here, that means the document
has been created. So we can return a response or concept JSON. And this will have a message
that will say, I'm going to put backticks, because we're going to put a variable inside
of here, I will say document. And let's do dollar sign curly braces to pass the ID of
the document, which is a property in a document reference type, we'll just do doc.id. And
we need to say create, we're going to say created successfully.

Now, if there was an
error, okay to catch error, for some reason, or do console dot, actually, let's return
a response. So we will do rest rest dot JSON. And by actually not, because there was an
error, we need to change the status code will shouldn't return the status code of 200. Which
means success. Let's do dot status. And let's give a status code of 500. Because this is
a server error. And let's give a JSON object that will have a error, prop property or key.
And this will say something went wrong. And let's actually console error it as well.
Okay, so let's save. Now we can run Firebase deploy and test it. There's nothing wrong
with that. But deployment takes some time, we can instead run Firebase, which will serve
our application locally, which is so much faster and will give us the ability to save
and then immediately serve again and we don't have to deploy each time we make a change
and we want to test. So now this is gonna serve locally. A using our machines server
Give us the endpoint. So let's take the Create scream endpoint, as you can see, says localhost
instead of the endpoint that we had earlier, and open up a new tab.

And let's test this,
let's change the type of the request to the port to a post request. And let's give it
a body, we're going to click raw, and select application slash JSON. And let's give this
a body of new scream. And let's give this a user handle of a say knew less than the
request. And, and it says document something, something
created successfully. And if we go to our Firebase database, and we check, I don't know
why I click that it shows without us reloading, and there we go, our new screen is here. And
what's beautiful about this, put them side by side. And we say new screen too. And we
click Send, it updates in real time. And we see oops, we see new screen too. Fantastic.
Now, we shouldn't there's a problem here, which is that if I would send a get request
to this, of course, without a body, it will say we have an error, like a server error,
when actually this is not a server, this is a client, we shouldn't send a get request
to a route that is meant for a POST request.

We can prevent this by doing this. So we can
say if request, oops, if request dot method does not equal post, we should stop here and
return a response. So res dot status, it's not gonna be 500, there's going to be 400,
which means this is a problem from the client. This is a bad request, as they send a Jason
with an error that says, method not allowed. Now, this will solve the problem of not having
to answer to a get request. So if we go to postman, and click Send, this time, it will
say method not allowed with an error code, rather a status code of 400. So you can start
to see how this is coming together and how we can send the request to fetch data send
request to persist data. And this is obviously just the start, we're gonna have so much more.
In next in the next video, we're going to start to implement express to so that we don't
have to say this f request method on each request, and we can group our requests and
handle them so much better use an Express.

So let's install now Express and make this
code look much better than it does now. So one problem with having our functions structured
like this, is that when we want to have two endpoints of our API, point at the same name
of the endpoint, but handle two different functionalities, we would have to put everything
in one function and check the request method and respond accordingly, which doesn't look
really good. So this is, this is one of the things that Express is going to help us with,
okay, so let's install Express. Let's go to the console and make sure that we are in the
functions folder, CD functions, and run npm install, dash dash save, save, Express. And
once it's installed, we can actually start bringing it in. And that's installed. Let's
do const.

Express, equals require Express. And when you have to initialize the app, let's
do const. App equals Express and call it like a function, because that's what it is. Let's
remove this comment and this hello world function. We don't need them anymore. And let's see
how we can change this route. So instead of get screams, we can actually copy this code
that's inside of the get screens route, and get rid of this. And we can do app dot get.
And we do slash screens. Because the first parameter of this function is the name of
the route. And the second one is the handler, which takes a request and a response, similar
to what we did like earlier. And here we're going to paste back the code that we had.
And now this on its own will not do the trick, we need to tell Firebase that this app is
the container for all our routes. Or actually the routes that are in the app. So we can
do exports. And this is one of the things that that express will let us do, because what
we want to have is one of the best practices for having an API is if we, let's say, have
an endpoint, HTTPS, and let's say our base URL is called base URL Comm.

We don't want
something like this straight away slash scrims. Because it's good practice to have slash API
and slash something. Because on the actual base URL itself, you might have your website.
But when you do slash API slash, whatever, you can have your API there. And some cases,
they do API dot base URL, but it's just different conventions. So we want to this prefix. So
what I'm going to do now is that we're going to do exports dot API equals functions.https.on
request. And here, instead of passing one route and one function, we just pass our app.
And this will automatically turn into multiple routes. And now if we save and when we deploy,
so we run Firebase deploy. It should prompt us a, it should ask us that, whether we're
sure we're going to delete the get screens function, because we just deleted that code.
Yes, it does, we will say yes, delete HelloWorld and get screamed because we don't need them
anymore. Okay, now that it's deployed, we can actually go to our Firebase console, go
to functions, make sure you're on that project.

And there we go, we have this one function
called API. And we have create screen and the other ones that we created are gone. Okay,
so let's actually test this. So we go to postman. And I believe, well, we will not go to localhost
because we didn't do a serve. So let's actually copy this. Oops, let's go to here and copy
this endpoint. Yep, from here and go to postman. And if we take this, we have to add our actual
endpoint, which is screams as we set it to be. And we send a get request. And we wait
for it. And there we go, we get our screams. And now if we send a POST request, it should
fail. And it does fail. And it says that the route was not found, which is cool, because
so now we don't have to do this thing where we do if request method equals post, don't
send an error, the like, express takes care of that.

Okay, so let's change the Create
screen route as well. So what we're going to do is actually just delete this part, or
just right up dot post. And the route would be slash scream. And this is the handler.
And here, I think everything is fine. We don't check if it's a post, because this is automatically
doing that.

And let's leave everything as is for now. And actually, instead of deploying,
let's just serve so that we can test it locally, we don't have to deploy. So we run Firebase
serve. So nowadays served and by the way, if you get a warning that your node version
is higher than the one that Google Cloud Functions support, don't worry about that. As long as
you write your code that is compatible with node six, and you don't use any features that
are not supported by node six, you should be fine. So let's copy this. And let's go
to postman. Oops, not wrong, postman. let's paste this here, because now we're on
the localhost.

And if we leave this as a POST request, and we add scream without an S, and
we give it a request body, and this request body will have a body new scream, I think
three, we didn't submit three, and the user handle and I say, Johnny Yeah, that's it.
If we send it should successfully create a screen. And yes, document something something
created successfully.

And if we go to our database just to make sure. And, or Zed there
is so screen three by Johnny. Brilliant. Okay, so let's go here. Let's actually fix up the
screams route. What I want to do is that on whenever we return a scream, I want to return
its ID as well and you'll see later why we actually need it. So here, instead of pushing
all what's inside of that screen, let's push an object. And this will have a scream ID.
And we will take this from doc.id.

That's the property that the doc document, reference,
or snapshot, rather has access to get the body, which is Doc, sadly, this is node six.
So we cannot use the like, maybe some of you are thinking, why don't we just do this? Like
doc dot data, which is called a spread operator and just spread all those properties. But
because this is node six, this feature is not yet supported. So we have to do we have
to do them one by one. So bodies doc dot data dot body, and user handle is doc dot data. dot whoops, though, use a handle. What else do we have
created art? Is dog data, dog created art? Think this is it? Yeah, this is okay. So if
we save now, when we get the screams, forgot to postman when we get the screams. So let's
add an s here, make this a get request and remove the body.

We send this request, because
we're still serving, it should update. And there we go, we get the scream ID as part
of our screen. Cool. Now let's change something because there's a problem here, we want to
order our function, our screams, and we want to get the latest one first. So let's actually
ordered them by date. And we can do that by after collection screams let's chain a method
called order by.

And let's pass the property of created at make sure you don't misspell
anything. And this by default takes an ascending order. But we want descending, we want the
latest one to be first. So let's hit Ctrl. Save. And we go and we send this request.
And we should get the latest screen first. And we do the one we just submitted earlier.
Brilliant. Now one thing I want to change as well is that these created art, I don't
want to use the Firebase timestamp type, let's just use a normal date string, because that's
recognized in JavaScript.

And we can format it however we want. We want. So here, when
we create the scream, I don't want to use the timestamp thing anymore thing anymore,
let's just use new date. And let's just transform this into an ISO string. So dot new data.to
ISO string. And it's a function. So this will make it into a string.
And let's let me actually do that do something, let's create a file called DB schema. And
this, by the way, has no implications whatsoever on our code is just something that I like
to do, still let DB equal.

Here, we're going to write how our data is going to look like,
just as a reference thing, we're not going to use this file in anything. So I want each
screen to have actually, in the database, it's not going to have scream ID, we just
returned that from our code, it's going to have a user handle though, which we will use
to identify who is the owner of this screen. Let's make this an object like this. Like
this, okay, it's gonna have a user handle, and let's give this a dummy value of user,
it's gonna have a body give this a dummy value of this is the scream, body. And it's gonna
have a created at, and this is an ISO string. Now let's actually quickly like generate one
for this do new date, to ISO string, not ISO and string, ISO string.

Let's copy this, I
know you don't have to do this. But it just, I think it's a good practice as a reference
point, you don't have to open Firebase each time. One other property that we get one or
two other properties, actually we're gonna have, we're gonna have like count, she's gonna
be a number, let's say five. And we're gonna have common count. Now, this is good practice,
because each time we get a scream, we don't want to as well check the comments that have
the ID of the scream and count them and return that number because Firebase charges you on
the amount of reads that you do So you're trying to minimize the amount of reads that
you execute each time a user sends a request.

So if you store these here already, you will
avoid too many reads on your database and be charged less. Okay, so let's, let's just
leave this for now. So this is what our screens would look like. And yeah, okay, so this is,
let's test this screen, this post screen. Let's make sure it's still working. So let's
send a let's, let's open up a new tab. So we don't have to type the URL again. Okay,
so post, I'm gonna have a body of type application Jason. Let's give this a body of new scream
400. I don't feel creative right now. Use the handle of j Jane. And we send this request,
oops, not screams scream. We send this post request. And there we go. We get document,
something Something was created.

Let's go to our database. And now we see the new one.
And when is it the new screen for another created that is a string instead of a timestamp?
Cool. Okay, so I think this is it for this video. Oh, actually, one, one thing that I
want to add, for those of you that are not in America, and you're wondering why your
functions are being deployed to where is it to us central instead of Europe. By default,
Firebase deploys to us zone US Central one. Now, this is a bit of a problem, because it's
going to add, like 300 to 400 milliseconds of latency on each request.

Maybe it's not
a problem right now in testing, but later in production, this is going to slow down
your application. So if you are like me, in Europe, and you want to change deployment
region, you just chain after functions here, you chain, the method region, and you specify
the string, the name of the region, in my case, it's going to be Europe, dash, West
one. And by the way, you can go to Google Docs, Google Firebase documentations, to find
all the regions available. If you're in America, this doesn't apply to you just leave it as
is. By changing this next time we deploy, it can actually be deployed to the zone Europe, West one. In this video, we're going to start to work
on authentication. And on signing up users. In particular, let's go to our project dashboard.
Let's go to authentication and enable it by clicking here setup sign in method. And here
on email slash password, let's enable it and click Save. Let's go to our project settings.
And let's go here your apps.

And let's grab this config object. And let's go to our project.
Now, we're going to be using the Firebase library, which is a actually a client library.
But we're going to use it to sign in and sign up our users and get authentication tokens.
So let's CD into functions. And let's run npm install dash dash safe Firebase. Okay,
so let's initialize our Firebase application. This is important. So const, Firebase equals
require fire base. And let's do Firebase dot initialize up. And we need to pass it config
object.

Let's do const. And let's paste in our config actually not var const. And let's
take this config and pass it to as the argument to initialize up so that Firebase knows which
app we're talking about. Let's actually make this Express line. Mix Express into one line
by doing require Express and calling it on the same line. I think it just looks neater
like this and let's put it up here. Let's create our signup route. Let's delete this
comment. replace it with another comment saying sign up route.

And this would be a post route.
So app dot post. It will be slash signup. And the owner is gonna have a handler so request
responses the arguments. And now we need to extract the form data from our request body.
So let's do const new user equals an object. It's gonna have an email. If you remember
our form has an email password Confirm Password and handle field. So as to email equals request
dot body, dot email. comma, and let's copy this line and paste it three more times, select
Email, Ctrl, D undo password, select Email, control the Confirm Password, and handle.
We're not gonna validate the data for now. But let's write a to do here, validate data.
And let's sign up our user.

So let's use the Firebase package we installed Firebase dot
auth as a function like this dot create user with email and password. And let's pass it
exactly that. So new user dot email. And the second argument will be new use of password.
This returns a promise so as to dot then data, which I think it's credentials as user credentials,
so let's do it. If we are here, that means we've successfully registered so let's pretend
a response response dot status of actually 201, which means a resource created as give
a JSON object with a message with a template string, because we need to use a variable,
let's say user.

And let's do dollar sign curly braces to use a variable data dot user dot
UID stands for user ID. And let's say signed up successfully. And course, let's catch any
potential errors. And let's console error, the error. And let's return res dot status
500 oops, 500 server error. And it's gonna have a JSON with an error. Let's pass the
error code. Let's return it in case there's any error. Let's save. Let's run Firebase.
So and see if this is working. Let's copy this endpoint.

Let's go to postman actually
already have it. So let's do slash sign up instead of screams. And it's going to be a
POST request. That's gonna have a body of type application JSON. So we're gonna have
an email, I'd say this is user@gmail.com. We're gonna have a password of 123456. Oops,
we're gonna have a Confirm Password, which does, which does nothing right now. But it
will later 123456. And the handle, which is going to be user, so listen, this
request. How do we get user, the ID of the user signed up successfully, and we get our
code of 201. Cool. So if we go to our Firebase project, let's close this. Let's go to authentication.
And there we go. We got our user with this user ID right here. Let's copy this user ID.
And I'll tell you why in a second. What we need to do right now is that Firebase by default,
doesn't allow us to store more information in about our users in the authentication collection.
But what we can do manually is we can create, of course, right now manually, but later programmatically,
we can create a collection here, we call it users.

And this will store documents for each
user, we will have one document that holds extra details that we need, such as the handle,
and later, like a bio image URL, any extra details that you want to add. So And the key
thing that I want to do here is that our users, of course, by default, because of Firebase,
even though we can change this, but by default, each user is rich, each email is restricted
to one user. So the email has to be unique. But we want to also have the handle as a unique
thing, like, of course, because this website is kind of like a copy of Twitter. So our
handles will be unique. So we can use our handles as the ID. So here, let's not to do
auto ID. And let's give the ID of the user that we just created, which is user as the
document ID.

And here we're going to have user ID key. and the value of that is the
ID we just copied. We're going to have a created art. And let's give this a timestamp the date
today and say I don't know midnight doesn't matter. Let's add another field. This is gonna
hold, what's this hold? Actually? Yeah, let's, let's put the email actually. Because if we
need it, we're gonna have it here. So user at email, calm. I think this is all we have
for now. So let's save. So now what we need to do each time someone signs up, we need
to check this collection. And we need to make sure that this handle is not taken. So if
right now if someone tries to sign up with a handle of user, or the desired behavior
should be, you cannot sign up because this handle is already taken. And if they tried
to sign up with the same email, Firebase will automatically give them the error. So let's
actually write the code that checks for the handle being unique.

Let's look at our DB
dot. Actually, we don't have DB yet. Okay, let's change something. I saw this in the
in the Firebase documentations. And I like it, let's do db, db equals admin dot fire
store as a function like this. And wherever we need firestore, we just do db.so. Let's
replace where they will find admin dot firestore. Like this, we'll replace it with DB because
that makes more sense. So dB. And there we go. Okay, so in our signup route, we need
to do DB dot collection, users dot document.

Actually, we can do document without collection.
So let's do DB dot document. And we need to pass it the path. So let's do a template string.
And the past will be slash users for the collection. And the document will be as the dollar sign
curly braces, new user dot handle. And let's do dot get. Of course, this returns a promise.
And this will hold a as we see here documents snapshot Yes, document snapshot. So doc. And
the way fibers works, even if this document doesn't exist, we'll have a snapshot.

So what
we need to do is we need to have a conditional here, say if doc dot exists, which is a Boolean,
if this document exists, it's true. So if this document exists, then this is a problem
because this handle is already taken. So let's return ress dot status of let's give 400 bad
request. And let's give a JSON response. And the way we're going to structure our react
app is that we're going to return a not an array an object containing errors. And for
If the error pertains to any field, let's say the error pertains to the email, the errors
name will be email. So in this case, the errors name will be handled, and the message will
be this handle is already taken. Alright. And if this document doesn't exist, then cool.
Let's create this user. So let's do here. So let's do Firebase. So let's do this Firebase
dot all of this Firebase Auth, create user with email and password, new user email and
this.

But since we're already in a then block, we need to return this return. So we return
this and then we chain another dot then. So that we will have the result or like the return
promise from this call here. Will which will hold data as to here. Now this, if we get
here, that means we have our user created. What we need to do now is I want to return
an access token and authentication token to our user so that the user will later use to
request more data. So we can do that by we know that in data here, we have access to
the ID. So let's do user ID equals data dot user dot UID for user ID.

And we can do data
dot actually user ID, or is it user ID. Actually, we can even call it on the user itself. We
don't need this. So we can do data dot user dot get ID token.
Right now, it's not recognizing the, the type for some reason, but this should work. Get
ID token. And this, this actually is a returns a promise. So let's do return like this. And
you're like this and then let's chain another dot then and this will have token, so token,
don't know why the types are not being returned, being displayed properly. But let's just go
with it. Let's return the token. So let's return a response to JSON. Let's give the
status again of 201. json token, we can just say token like this because the name of the
property and the name of the value are the same sort of token like this should have the
value of our token.

Okay, let's delete this code here. And let's do a dot catch error.
In case any error happens. Console dot error, the error and return as a response res dot
status 500. json with an error, error dot code. Cool. Okay. Let's actually let's not
put them side by side, let's run the same. Let's actually register a new user. So let's
say new att email, same password and the handle is new. This should return us a token. And
it does. So we have an access token right now. And this we will use to use whenever
we need to access a router that is protected. Okay, let's try to actually register a user
that already exists. So let's send the same request. So send we should get and there we
go. We get an internal server or email already exists. Okay, so we shouldn't this shouldn't
be happening we shouldn't get Actually no, this should be happening because it's the
error from here.

So let's handle it here. We want we don't want to return like this.
We want to check if the code of the error is this code exactly here. That means it's
not a server error is just actually, it is a client error, technically. So what we need
to do here, we can do if error code, no code equals the string off email already in use,
we need to return. Yeah, I think 400 less give a res dot status 400 dot JSON. And the
error pertains to email. So as the email, we say, email is already in use. And if it's
anything else, so else return this. And do we do we handle any other errors? I think
we don't.

Okay, so let's go to postman again. Listen, this request. Cool. ml is already
in use. Now, we haven't yet created a field for this, we need to create a new field a
document for our user whenever the they register. So let's do that. So right here, before we
get the token, do we do it before we get started? Or should we don't we don't return this token
here. So let's store it in a variable. Let's do here. Let's token initialize token here.
And then here we have a student token equals token. And here instead of returning a response,
let's, let's, let's do const. user credentials. equals and let's create our user document.
So this will have a handle of new user dot handle. And we will have the email of new
user dot email. And we will have created that which will be new date to ISO.

Why do I always
type the end after ISO? Okay, the ISO string, make sure you didn't misspell anything. And we need the user ID here. Us user ID or
actually how do we access the user ID, we need to put the user ID as well in a variable
so that we can access it. So let's declare the user ID here. And we have access to it
here. So let's do user ID equals data dot user dot UID. And then we use we use oops,
on this user ID We can just do this, because it's the same name. Okay, here we are. Now
we need to persist these credentials into a document in our collection in our users
collection. So we need to do DB dot document.

And this will be in the users collection.
Don't forget, by the way, thing, template literal string, slash user slash. And we'll
give it we'll give it the handle as the document ID. So this will be new user handle. And we
need to do dot set, which creates the document, unlike get, so let's pass this user credentials.
All this returns a promise, I keep forgetting. So to return it. And then let's do yet again,
another than promise you, I'm pretty sure this is the last then what do we get? We get some data here. What
type of data is is the right result, this is actually useless. So let's just not even
use it. Okay, return rest rez dot JSON. dot status, let's give the status. I don't I can
just return 200. But I just like to return to a one once something is created. So status
to a one JSON. And we need the token. So token. Yeah, this will work because it's the same
name.

Yeah, same name that property. And let's save. Let's actually, let me delete this.
Let's delete the entire document or the entire collection. And let's delete these two users.
Because I don't want to keep coming up with new emails. Okay, let's test this out. Make
sure we saved we did. Or I did make sure you save as well.

Let's do this as user again. user has to be the first one. Okay, sent Let's cross our fingers. And hope
for a token and we get to a one button empty object. Interesting. Let's go here. Refresh.
We get our user we go to the database. Users collection has been created cool. And the
ID is user. And we have the details here. Everything is fine. But why don't we get the
token back? Okay, so the problem was variable naming ambiguity.

I named this token and this
was token as well. Okay, so this is token now. And then I renamed the return from the
promise to ID token and then assigned token, this token to this ID token, and then here
as the response return token, which will hold the value of this. And if we test this, we
go here and we do new five, I don't know, new five, and we post and we get the token
back cool. In this video, we're going to be implementing
validation to validate the data that's coming in and making sure that it's valid before
we do anything related to our database.

And we're also going to write a login route where
users can log in. The reason one of the reasons why we need validation is that, for example,
if I would do this, I'll give an empty email, I'll give a handle that exists, it would already
go and check, oops, I need to run Firebase serve. If I would send data without an email,
but with a handle that exists, it will already go because of how our code is structured,
check whether this handle is taken or not, instead of just stopping here and saying that
the email must not be must not be empty.

So if you would give as well, no handle, he would.
I don't even know I would would do which is give us like some word error like this, I
guess. Yeah, the value of the argument or something like this, but we need to just validate
everything ourselves and return errors accordingly. So yeah, the document path. Yeah, it was.
We gave an empty string right here and it caused the problem. Okay. So what we need
to do right now is we need to follow the each field. What we want to do is that we need
to make sure that email is not empty and email is actually in a valid email address, and
password and confirm password and handle all of them.

We need to make sure they're not
empty and We need to make sure that the password and the Confirm Password match saw the same
value. Okay, so let's start implementing. So let's start working on the email. So we
need to make sure that it's not empty, let's write a helper function that lets us determine
whether a string is empty or not. So let's do const is empty, which is a function that
takes a string and does the following.

So it does if string dot trim, oops, not string
dot trim. So we need to make sure that we eliminate any white spaces, because someone
can submit like one space, and that would be considered non empty, and we don't want
that behavior. So we need to trim. And if it equals an empty string, then return true.
Else return return false. Simple as that. Okay, so here, what we need to do is, we need
to say if is empty new user dot email, then we need to return all the errors together.
So what we need to do here is we need to declare or how do we say initialize an errors object
and set it to an empty object. And here, if we have an empty email, if the email is empty,
we need to set a property in this errors object and say errors dot email equal, say email
must not be empty.

Now, if it is not empty, then we need to check whether it's a valid
email. And we need to check for empty first because we don't check whether it's a valid
email if it's empty anyway. So here we do else. If, and here, we're going to use another
helper method. So let's create that now. And this method would be ups const is email equals,
and it takes an email as an argument, and it checks whether this is a valid email. Now,
we could use like a validating JavaScript library, but there's no need, we just need
these two helper methods. So what I'm going to do is I'm going to paste here a regular
expressions. So let's do a const. Reg x equals all of this, and I'll post this in the video
description. Don't let this intimidate you. It's just a regular expression that matches
for a pattern of an email. So what we will do here we'll do f email, which is this string
that we pass to the function dot match, which is a function that matches a string against
a regular expression.

And we pass it our regular expression right here. If they do match, then
we return true. That means this is a format, the string is formatted as an email, it is
a valid email. And else return false. What did I do? true false, return false. Okay,
cool. So here, we do else if is email, or, rather not is email. So if it is not an email,
and we pass new user dot email, if it's not an email, we do errors, dot email equal must
be a valid email address. Okay, so this is for the email. Now let's do the other three
fields. So first one is password. So if is empty, new user dot password, dot password, then errors dot password, we can just do a line
like this equals must not be empty.

And let me by the way change this too just must not
be empty. Because on the front end, when you have an email input that says email on it,
it's not it doesn't look pretty when under the email as well, there's another error message
saying email must not be empty. The user already knows that this is the email field so it's
more proper to say just must not be empty. And this isn't the must not be empty.

And
do we do the same? We don't do the same for password for Confirm Password rather. In fact,
we will just check if they are equal to each other. So what we need to do is that if a
new password or new user password does not equal, new user, Confirm Password Then errors
dot Confirm Password equals passwords must much all must be the same, it's up to you. Okay,
the next thing is the handle. So the handle must not be empty as well. So we can just
copy this and paste it and replace password with handle. And now what we need to do is
that here we have this errors object, we need to make sure that this errors object is empty,
that means there's no errors, that means we can proceed with the rest of the logic.

Otherwise,
if there is a key in this error object, that means we have an error, we should just break
here and return. So we need to do is that let's do an if object with a capital O, because
this is a JavaScript namespace, or class rather object dot keys, and we pass in errors. dot
length, we need to make sure that the length of the array of keys is not equal is not bigger
than zero. Because if it is, that means we have some errors. If it is bigger than zero,
then we just return res dot status of 400 or JSON, and we pass it the errors. I think
this is it. So let's actually test this.

And we save and we go to postman. And here let's
send just empty values like this. See what happens. Cool. We get email and password unhandled.
We don't get confirmed password. But that's okay. So let's try to give it a an invalid
email. thread. Let's give it a password. But no Confirm Password. Cool. must must be a
valid email address for email, Confirm Password, it says passwords must match. That's actually
must much password. And says, Yeah, okay, so that Confirm Password error is gone. Now
let's give a valid handle. Now, Oh, I forgot to change the address. So let's give a valid
email address. And now it should go through cool, it still gives us gives us another error.
But this is from later on when we check whether the handle exists or not. Cool. So our validation
is working. One thing you do have to note though, if we give, if we miss out on a key
and not pass it, it will, it will have an internal error and not report anything back.
But I'm okay with this.

Because we will be the only people consuming our own API. So
that so we will make sure from the React side. Because it's an HTML input, it will never
send a key that is undefined or no, it will send an empty value, but it will still send
that key will just send an empty value. And then we'll get the error, the proper error
validation. So we shouldn't worry about that. Alright, so that's validation done for our
signup route. Let's actually write the login route. So let's scroll down here. Let's do
up top post. And this will be slash login. This will have as per usual, or request the
response for the handler. And we need to now validate the data for for the login and the
login takes two things an email and a password. So let's do const user equals and this user
will have an email from the request body. Sure, can we use Never mind actually request
dot body dot email.

And the password is request dot body password. And here we do validation
as well so that errors equals an empty object. And let's do if is
empty and we pass user dot email. If it's empty then errors dot email equals must not be empty. And oops. And if copy the same thing
actually. Let's select Email Ctrl D and do password and password must not be empty as
to F object. Keys. Pass errors is bigger than zero oops,
what am I doing length is bigger than zero, then we need to return res dot status 400.
And the JSON errors. So here, if we don't have any errors whatsoever, we need to actually
log in the user. So firebase.no actually dot auth dot sign in, sign in with, with email
and password, and then pass those.

So user dot email, and then user dot password. This
returns a thing, a promise. So then data. And then we need to do the same as in the
sign in as in the signup rather. And we need to return the token. So what we need to do
here is the return data dot get ID token. And chain another dot then, and this will
have the token. And we just do return rest dot. Jason, I don't need this to do status
code. And we just put token like this. Catch, we have any error, the usual console. log,
not log error, rather. Error. And res dot status 500 dot Jason. Error. Error code. Alright,
so let's test this out. We save and we're still serving. So let's go to postman. Let's
check which uses we have forgotten. So we have used that email Comm. So let's go here,
change this to login. And what am I doing? Wrong? Yeah. What's happening? What does it
look like this? Okay, so Oh, yeah.

Application JSON. Email is user and password is that we
hit send. And we should get a token, and we don't we get an internal server error. Why
is that? Get ID token. Okay, because it's data dot
user. dot get ID token? Because go back, postman sent, and we should get a token. Cool. We
do. Let's test out the validation. So empty email. Yep, must not be empty and the wrong password.
Oh, we should handle this, actually. So let's go here. If we have an error, let's do if
error code equals this code that we just got. Then return response dot status 403. Which, which
is, which means unauthorized and Jason error, actually not error, let's say, give general.
And this will make sense later.

Let's say wrong. credentials. Please try again.
And if it's any other error, we'll just return it. So else like this. return that. And let's
say but let's test it. So the same input, let's hit send. And there we go. We get wrong credentials.
Please try again. Cool. So now we got the login route working and the signup route.
And we have validation. Yeah, we're done for this video. So in the next one, we're going
to be implementing middleware, we're going to be making sure that each time someone says
because right now our send post, submit scream request, router router is not protected. So
we need to make sure that whenever someone submits a post, they are actually logged in
so that this route is protected.

Okay, so so far in our application, we have two routes,
the slash screams, which gets also the screams and the slash post, I mean post at slash scream,
which both one scream. Since we have already implemented authentication, it would be nice
to have some code here, that would check the authentication token that's being sent from
the user to see whether this user has logged in or not. Because this should be a protected
route, we don't want anyone posting screens to our database, they have to be logged in.
That's one functionality. And the other functionality would be, we need to extract the user handle
from that data, and then submit it into our database.

So if you were to look at our database,
our screens are stored, having one property inside the document saying, that's called
user handle, which has the handle of the user so we can know whose screen that says. So
the way this this is done is that whenever we post a request to a protected route, we
need to add a header called authorization, right? Like this. And we will have a value
of bearer space and then a token right here. So it would be something like this. But of
course, this would be an actual token. So let's actually write code that would the code
of this token or like obtain this token and get data from it, and make sure that our request
is authorized. Alright, so we would actually, we could write the code right here. But since
we need this functionality for multiple routes, then we need to make this into a function,
and then run it, chain it before any request. So let's actually write this in a function.
And the way Express works is that we can pass a second argument to, to this post, or any
actually any route.

And this argument would be a function that does something that intercepts
the request, and then does something depending on what the request has, and then decides
whether to proceed towards our handler, or to stop there and send the response, aka middleware,
a piece of middleware. So let's, let's call our middleware, which we haven't created yet,
if the auth for Firebase authentication, and let's create her so let's do const. So it's
going to be a function const, FB auth equals, and it's going to take three things to you've
already seen the request, and then the response. And the third one is called next, which is
gonna, which is something that if we return it and call it as a function, it's going to
proceed towards our handler right here. And we can chain as many pieces of middleware
as we need.

But in this case, we only need one. Okay, so here we have access to our request
object, what we need to do is that we need to check if request, oops, no, not release
requests, dot headers, dot authorization. So if this exists, and we need to check now
we don't have to do the bearer thing. But it's a convention and in multiple frameworks
and other languages, and it's a good it's a good standard good convention that everyone
follows that your token has to be, has to start with the bearer space string.

So what
we need to do here is we need to do another check another condition, which is request
dot headers, dot authorization, dot start with, which is a JavaScript function that
checks that a string starts with a certain other string. And let's do bearer space. Now,
if of course, as it suggests, if our string starts with bearer space, the and and it exists,
then this condition is satisfied. So we'll go in here. And actually, we need to initialize
a ID token variable here. So let's do a lead ID token. And then here, if these are true,
that means our ID token equals request dot headers, dot authorization. Now remember,
we need to extract it, we need to extract it because there's a bearer space before it.
So what we need to do is, we need to do dot split, which is a JavaScript function that
splits a string by a certain other string. So if we split it by bearer space, that means
it's going to have an array of two, it's going to give us back an array of two strings.

The
first one is bearer space, and the second one would be the left, which is the token.
So as to one that means we want to take the the second element, which is the token. And
now that we have our token, we can proceed with our logic. But we need to do an else
statement here. Because if we don't have an authorization header or it doesn't start with
bearer, we need to actually stop the request here and send back an error. response. So
let's do return response dot status 403 because this is an unauthorized error, let's do Jason
with an error that says on, authorized. misspelled that unauthorized,
cool. Okay. And let's actually console log This Just In Case console, or console error.
Unless so Oh, no.

Token found. Alright. So here, if we pass through here, that means
there is a token. So it's not enough that there is a token, we need to actually verify
that this token was issued by our application and not from somewhere else. So what we need
to do is that we need to do admin dot auth. And here we have a function called verify
ID token. And we will pass it our ID token, ID token. And this returns a promise. So we
do then. And this promise holds a decoded ID token, as you see here.

So let's do decoded
token. And like this. And then here, what we need to do is we need to this decode the
token holds the data that is inside of our token, and which is going to be user data.
So we need to add this data to our request object so that when this request proceeds
forward to let's say, this route, our request here will have extra data that we've added
from this middleware, and this case is going to be user data. So what we need to do is
the request dot user equals decoded, decoded token. Did I misspell that? No, it's fine.
Okay, so decoded token. And we also need to get the handle, because this by default doesn't
have the handle because the handle is not stored in Firebase authentication system.
It's stored in our collection users. So we need to actually do a database request as
to return DB dot collection users.

And we've also stored user ID in our users collection.
So we can do where user ID equal equal equal equal. And we already have the user and the
request. So we can do request dot user. And this will have a property of UID. And that's
actually here, let's console log the, the decoded token just so that you see what it
looks like. Okay, so now where we have this, we need to limit let's let's do a limit one,
which, which does exactly that limits our results to just one document.

And let's run
get, and then let's train another, then we get data back. And because this is a a DB
dot collection, query, and we using where, even though that we've limited it to one,
this will still have a Doc's property, which is an array, and of course, it's going to
have only one element. But to access it, we need to access the docs.

So we need, we want
to add a property to our request user. So request dot user dot handle. And let's do
equals data, dot Doc's, the array, and then we take the first element dot data, the function
which extracts the data from this document, dot handle, I believe we have a handle, I
think, let's check in our users. Yeah, we have a handle property. So we're getting this
object and then we get in this property and attaching it to our request dot user. Cool.
So now here, when we got here, we need to return next as a function like this, which
will allow the request to proceed towards here. So now that we have this setup, actually,
let's handle the catch block. Because here if it verifies the token and the token, and
it fails at verifying it, that means this token is either expired or blacklisted, or
from some other issue. If it fails, it will come here. And here we catch the error. And
we need to send the error, an error an error. And let's actually console error.

This error
and let's say error. While very fine. Oh boy, very How do you spell verifying, verifying
token And we put the error like this. And let's do return response dot status. Again,
a 403. And Jason error is already adjacent, so we can just do this. And then Okay, so
this is done. So here, now, this means in this route, or in any other route, where we
add this FB auth as a middleware, if we get here, by the, by the time we get to this block
of code, we've already been verified.

And we've already it's already been checked that
we are authenticated. And we have access to request dot user. So what we need to do is
here in user handle, we just need to do because we have this user now. So we just need to
do request dot user handle, because we have we've added it to our request thing. So for
our post request, we just need to send a body and that will be enough. Alright, so let's
actually test if all of this is working. So we say then we do Firebase serve. Okay, let's
copy this endpoint. Think I already have it on postman? Yes, I do. Let's log in to get
a token. So the same data is still valid. Apparently, it's not Oh, yeah. Okay. I just
needed to correct the password. Okay, we get a token. Let's now send a request to slash
API slash screen. And it's still a POST request. And here, we have an authorization header.
With the value bearer, let's actually test like a random value here, so that we further
on purpose.

And our body would have a body property of body and it says, another screen submitted, I don't know. Okay, let's
send the request. And it felt the coding Firebase token fails, cool, we get this error 403 forbidden.
And if we were to give the correct token, so here bearer space, this token that we got,
and we send, it should be successful, cool document something, something was created
successfully. And notice, we didn't even have to send the handle. And if we go to our database,
in screams, and if we sort them by created at the sending. So this is the latest one.
And there we go, we have the user handle user, because that's the user we use to log in with.
And yeah, it's submitted and everything works. Cool. So we've already we've set up our authentication
middleware. So whenever we have any protected route, we just need to add this. And there's
your decoded token, it's got some token metadata, like the user ID, the expiry time, the email,
and any other user extra data that you would add.

So before we start to write more code,
and more routes and more functionality, let's start to refactor our code and organize it
so it's actually easier to maintain and to work with here, let's create a folder called
utility or util. And here, let's create a file called admin dot j s. In this file, we're
going to put, let's see, let's take a stick admin. So cut and paste it here. Let's take
where we initialize the app. And let's take the creation of dB. And now we need these
two admin in dB. We need them we need to import them in other in other files.

So what we need
to do is the module module, dot exports equals this admin, and dB. Alright, so next thing
is we need to separate the routes for screams and the routes for users to two different
files. So here in functions, I'm going to create a folder called handlers. And inside
of handlers, I'm going to create a file called screams dot j s. And another one called users.js.
Okay, so let's take the So here, we don't take the whole thing, we just take the handler,
and I'll show you why in a second. So we just take this chunk of code, and let's go to your
screams. And let's do exports dot. What was that? That was slash scream. So let's call
it get all screens equals the following. Now, of course, we need dB. So we need To import
that, so let's do const DB equals require. And we require that we go back one level,
and then we require that file created the admin file. So utils dot admin. Alright, so
here, what we need to do is that we need to do const get all screams, which is that handler
function.

And let's do require equals require one on the same directory slash handlers,
handlers slash screams. And then here, we just give it the get all screams, function
reference. And let's call, let's put a comment here and say, scream. routes. And this, there's
another one here. So we take the handler, we leave the middleware. And this is post
one scream, let's call it, let's call it just that post one, scream.

And let's go to the
screens, and do an exports don't have to worry about formatting because prettier will do
that for me. So thanks, ex post, post, one screen equals all of this. And we save and
it formats. I go back to index, let's copy this, or cut it, split it with the screen
routes up here. What else we have? Let's forget about this for a second, we have the post
signup route. So let's take all of this. It's actually a lot of code. And let's call this
signup, which we haven't created yet. But we go to users. And we say exports. dot signup equals all of that. And exports now export.
So here we need, what do we need? We need dB. Do we need admin? Let's search for admin.
We don't need admin.

Let's remove this to do because we've already done that. And let's
bring in dB. So const dB, Rick, because require, go back to one level and do slash detail slash
admin. One thing one other thing we need here, I think is Firebase. Yeah, we need Firebase.
So we can do here five days, or construct a const. Firebase equals require the package
Firebase and Firebase, let's initialize it. So Firebase dot initialize up, we pass it
config. And it's good practice to put the config file separately. So let's do const
config equals require. We haven't created this yet, but we will in a moment.

So we go
back one level, and we go into util. And we do config like this. Let's create that. So
here we do config dot j s. Oops, what did I do? No, not conflict slash j s. Let's delete
that. Or let me delete that you probably didn't make this mistake. So config dot j s. Let's
go to the index. Let's grab this. So go to config and we do module dot exports equals
this. And, okay, so what's next? Okay, let's bring in the signup handler. So const. Sign
up. Let's do login as well, which we haven't created. But we will, because require handlers
slash users. Okay, so let's take the login handler as correct and right login instead
of it. Let's do this. Let's go to users. Still exports got login, equals all of that. And
we need Firebase we've already instantiated or initialized rather Firebase. Do we need
admin? We don't. Okay. So in the index, now we have these helper methods.

Let's take these
routes, let's put them let's put them here. Let's call these users routes. And let's take this off middleware Ops, pay, copy
all of it. Now let's create a new file called FB auth dot j s and you Let us do module dot
exports equals equals all of that equals all of this. And what does it need it needs admin.
So we need to import that const admin equals require admin, which is in the same directory.
Okay, so let's take these two helper methods, or functions. And let's create a validation
file or validators, validators dot j s. And let's have these two functions here for now.
Let's go to screams. Not screams users. So let's take this validation from here. Let's
copy all of this. Okay, let's see how we can do this. Let's copy all this. So this is for
the signup route. So let's create a function exports dot let's say validate, sign up, like
signup like this signup data equals, it's a function that takes data and does the following.
So we have errors.

And here instead of new user, we just say data. Wherever there is
a new user, we put data. And the thing is we don't return status or anything from here.
We will return errors. But let's also return another key with errors. So let's do what
do we do? Let's do return error errors. And along with errors, we return another Boolean
called valid. and the value of this is this. Actually, let's compare it to zero. So if
we have zero then or do we actually need to put the ternary operator? Actually, let's
do because it might be a different data type. So So if it's if there is no keys, it's true.
Otherwise, it's false. Because if there's no keys again, in errors, that means there's
no error, that means the data is valid.

So we return this object that contains the property
valid. And if it's the property valid is true, that means the data is valid, then we should
carry on with whatever that's happening in that function. Or in that handler. Okay, so
I think everything is okay here. So we need to import this. So we go back to users. And
let's do right here. Let's do const, validate signup, data equals require. And we go back
one level, and we go to util slash validators.

And let's do as well, validate. Do we need
to validate login data? Yeah, yeah, by the login data, which we haven't created yet.
So here, in the signup, we'll do const valid. So we this is called destructuring. Because
we're going to extract valid and errors from validate signup. Like this. Yeah, it's like
this sign up. Data. Why is it not? suggested I misspell something here. I did. Okay. Oh,
actually, wait, sign lots sign like this. Yep, sign up data. And we pass new user. And
let's correct that because here we call it like something wrong. So sign like this, or
I called it. Let's create also. Okay, so here, we need the conditional, so if not valid,
then we return result dot Jason, or that status first. of 400. Got Jason. We passed the earth.
Otherwise, we just carry on. So let's do the same thing. Let's copy these two lines here.
Let's go to login. And here we do like this.

But instead of sign up, we say login. And we pass user, not new user. And everything
is fine here. Let's copy this logic here. And make it into a function and validators.
And the fun shall be called exports dot function will be called validate login data. And it
will take data and it will do the following errors. Let's do the same thing here. So return
errors and valid. Okay, so did we also in the index we need to import the auth middleware
authentication middleware. So const FB auth equals require you to slash util slash FB
off like this. Let's save everything.

Let's see if it works. Firebase. So let's see if
I didn't mess up anything. Okay. config is not defined index. config. Oh, we
don't need to initialize Firebase here. Excuse my dog. Okay, we need to bring post one scream
actually. Let's try again. One more time. All right, let's copy the URL. And let's go
to postman. Let's try to fetch all the scripts. So get
through the authorization header, even though it doesn't matter. Okay, fetches all the screens.
And we tried to go to sign up. And it's a POST request to give a body. And here let's
give it an email. Give it like something wrong. SATs. Password 123456. Let's give a Confirm
Password. The same? Actually, let's try the validation. See if it's linked properly. So
handle let's say new. Let's send. Cool. Okay, so let's give a valid email. So new at email
calm. And the handle is new. And we give same password we hit son.

Cool, and it works. So
as you can see, now our code is looking so much better, like the index file is so minimal.
And everything is now separated into their respective files. So now this will make it
so much easier for us to work on our routes. And we know where to go if any error happens.
So now that we have our handlers for our route for screens and users in two different files,
who can actually start to add more routes to further enrich the functionality or up
Alright, so before we do anything, I want to like fix two things that I they forgot
to fix. So here in the auth middleware, we need to actually import DB because we need
it right here to access our database. And in validators here, when validating user data,
we don't check for user email, we check for data, because that's the name of the argument.
Cool.

Alright, so the thing that I want to work on this video is setting a route for
users to upload the profile image to so let's do that. Alright, let's create a route here.
And the users route is going to be a post route. So slash app dot post is going to post
to slash user slash image. And the function is going to be called upload, upload image.
And let's import that from our not from users. So upload image Let's actually create
that let's save this and close, close this, save this and close this. Well, let's go to
users. And here at the bottom of users, let's create this function exports dot upload.

Image
equals, it's going to take a request response and an error function and it's going to do
something. Alright, so for this, we're going to need the package called, well, there's
multiple packages that do this, but that we're going to install something called busboy so
and make sure that you're in functions, and run npm install, dash dash save bus, boy.
Alright, so if we look at the documentation for bus Boy, you just install it, and you
in your function, ignore this HTTP thing because we're already in a handler in your function,
you run this on event on file, and then you handle the file upload, and then you run on
finish.

And then you stop the process. And you upload your image using whatever library
that you're using. In our case, it's Firebase, or the Admin SDK. Alright, so let's do const.
busboy equals require bus, boy. Let's bring in a couple of other things. So const path
equals on path is a default package that's installed on any node. Node project, spring,
another default package called OS. So OS equals require OS. Another one, it's Fs. Triple D
stands for file system. Alright, that's all the imports. Let's instantiate an instant
instance of busboy color. busboy equals new bus, boy. And this takes an options object
mainly had his item in it, and this is going to be we're going to give it the our headers
that we got in our request.

So request dot headers. And here, let's do our own file event.
So busboy.on, and the event name is called file for file uploads, and the handler is
going to take a couple of things. So first one is field name. And as you see here, second
is file. Third is file name. Fourth is encoding. And fifth is MIME type. Now, and don't be
overwhelmed by this, we don't need all of these, we just knew the file name, your file
name, and MIME type.

But even though that we don't need encoding, for example, we can
just do this because otherwise MIME type will have the value of encoding because it's the
fourth argument in the handler or in the callback function. So here, we need to get the extension
of our file or of our image file. So let's do const. Image extension. Extension. Yes,
public correctly equals, now let me show you how we're going to extract this. Let's say
we have an image file called image dot png, or not orangey. png, we need to get this PNG
or if it's a JPEG, we need to get the JPEG. What we can do is, we can, the problem is
we can have an image called for example, my dot image dot png. So what we need to do is
we need to split this string by dots on each.so. Let's do is a file name, your file name, dot
split. And we pass this a string and not a string, a dot. And here we have an array of
strings or strings.

So we're going to have an array that we'll have for example, in this
case, it's going to have the first value is my second image. And third is PNG. So we need
to access the last one. So here, this is an array, so we need to access the last item,
which is going to be file name dot split by dot again, dot length minus one. All right,
so here, this is gonna give us the index of the last item. And then this will give us
the value of that which is going to be either PNG or JPEG or whatever. So here we need the
actual image file name. So let's actually actually create one so const or we call it
image or image file name.

And let's just give it like a random value. So math dot random
times, times, I don't know 10,000 billion. Actually, we need to run Under this to get
rid of the decimals, so math dot round surround all in math dot round, like this. And we need
to concatenate a dot and concatenate the extension. So let's make this into a template literal
string. And make this into a variable like this with dollar sign curly braces, let's
add a dot and do another dollar sign curly braces and add the image extension. So an
example of this would be like this. So it could be like some random numbers dot png.
Alright, so let's close the template string. And let's do a semi colon. And now we need
to get the file path. So let's do const file path equals path, dot join, join. And here
we need the OS namespace, OS dot temp there for temporary directory, because this is not
an actual server, but and, but a cloud function.

So let's do image. We can catenate image file
name that we just created. And then here, we'll create a way actually, what am I doing?
Yeah, we're gonna need image file name and this object that we're going to create later.
So let's actually declare them, we're going to need them in a different scope. So let's
declare them here. So let's do let image file name. And we're going to need something else
called image. Give it a more expressive name.

So image to be uploaded. and initiate, initialize
it as an empty object. So here, we need to actually create this image to be uploaded.
So image to be uploaded. It's an object and it's going to have two properties, the file
path with the value of file path, so we can do it like this. And the MIME type. Let's
console log this, so that you see what these values actually hold. It's useful to sometimes
do it. So field name, we don't need file because it's a weird to where doctor console dot log,
file name. And console dot log mimetype. All right, we don't need the rest, we just
want to see these values.

Okay, so now that our file is created. Now, I mean, our object
is created, we need to use the file system library to actually create this file. So let's
do file dot pipe, which is a no j s method. And we pass it Fs dot create, write, stream
stream. And inside of the stream, we give it our file path that we created.

And now
this is going to create the file. Now after this event is due busboy.on. And this event
is the finish events. Once this is done, this will be executed, it's going to have a callback
that doesn't take any argument. And here, we need to upload this file that we just created.
So admin, that, Oh, we don't have admin, we need to bring admin in. So here we bring admin,
let's go back down. So here we do admin, dot storage.

Dot bucket, dot upload. And this
takes a file path or a path string called here, which is going to be image to be uploaded
that file path. And the second parameter or argument is an options object. And there are
a couple of options, but we just need resumable resumable. And we give this value of false.
And we need an object for metadata, which holds and by the way, this stuff is in the
Firebase Admin SDK. documentation for now, I really suggest you look at that because
it helps understand what what the hell we're doing. So this metadata holds another object
called metadata. And we're gonna have a key called content type that I'm spelled correctly
I did and this will have the image to be uploaded, dot MIME type.

Alright, so this upload function
returns a promise. So we change then and I believe we don't need anything from that.
Yeah, so we just go like this arrow. And here, what we need to do is we need to construct
the image URL to add to our user. So actually, yeah, yeah, we need to do const. image URL
equals, and this will be template string, HTTPS, colon slash slash. Was it for Firebase
Storage dot Google. Google API's dot com, slash v zero. And I'll show you in a second
how I know that this is a thing, slash v zero slash b slash dollar sign, curly braces to
put here, what we need to put is forgot to the conflict file, find that we have a storage
bucket key.

So we need this. So we need to do we already imported it in this file. So
we need to do config dot Storage bucket. And we need to keep on going so slash Oh slash,
here, we need the image URL that we just created. Now, we need to know we need the image file
name. So image, file name. And this is why we created both of these outside of this scope
so that we can access them here. Okay, so image filename, and we. This is not actually
we need to chain alt, this URL parameter alt media, alt equals media. Because if we don't,
whenever we access this URL, without the ultimate idea, it's just going to download the file
to our computer instead of showing it on the browser by adding this alt media actually
shows it on the browser.

Alright, so this is the image URL we need to do now is we need
to add this image URL to our users use a document which is right here. So let's go to our database.
Our user here needs to have a key called image URL, and we'll have this value. And so here,
what we need to do is we need to do return Doc not.db dot doc, and this document would have
so template string, you the path for this document is slash users. So in the users collection,
slash dollar sign, don't forget that this is a protected route, if we go to admin, and
non admin index. So in the index, I actually made a mistake here. So this is a protected
route, we need to add our auth middleware authentication, middleware FB auth, because
this is we can't have anyone upload an image to our server, or to our storage bucket.

So
we add the middleware here. And because we've added the middleware, this gives us access
to the request dot user, because when we reach here, that means this has been authenticated.
And we have that user object. So here, we do request dot user dot handle, which will
let us access the document of this user. And instead of running get we run update, so dot
update, an update takes an object and in each object, you can do field and give it a value,
and it will update update that field with that value. So here, we need to update the
field called image URL. And of course, if it doesn't exist, it's going to create it,
that's going to have the value of image URL that we just created here. So we can actually
just get rid of this and put it like this. Cool, this returns a promise we already put
return was changed, then what does this have the right result, that's useless.

So just
don't take it away, just go here. And here, we just return res dot Jason. And it's going to have a message, this doesn't
matter, really. And let's say image uploaded, successfully. Cool. And of course, here, we
handle the error case. So catch error, console, dot error, error. And then we return res dot
status 500. And with a Jason with an error, error code. Alright, one thing I forgot to
do, actually, is that whenever a user signs up, by default, they should have whoops, here.
No, not postman here. So I click on postman again. I didn't actually that was a bug. Okay.
So whenever a user signs up, we need to add an image URL right here that will have a an
image that has like no face. I mean, this I don't know. How to describe this this thing
I've already downloaded, I'll put the link in description. So we want by default, whenever
someone signs up, we give them this image. And until they upload a new image for themselves,
they have this when they upload a new one, they will have the new one.

So let's actually
manually upload this to our bucket. So we go to storage. I think for you, you have a
blue button here says activate storage, I've already done that. And that's up upload this
file. And the no image file, I called it no dash image dot png, I'll tell you why matters
what I called it. So it's right here, it's in our bucket. Now what we need to do is go
back to our code. And here whenever someone signs up, let's give them this image. So after
the validation, let's do const image, or no image equals that name. So no dash image dot
png. And here when we create the entry in the users table, we are the key news is document.
Then why keep saying table? Because of SQL. Okay, so image URL, and the image URL would
be the same thing that we had we had here. Whereas this thing, so let's copy all of this. Let's go back up. Where are we? So right here, Storage bucket,
but instead of image file name, it's gonna be no IMG.

All right. And that's the comma.
Alright, let's test all of this. It should be working. So yeah, let's save everything.
And let's run Firebase serve. Not save serve Firebase serve. Let's sign a new user up.
Okay, so this sign up. And here we have given new@gmail.com password of that password. The
same thing? And, or not password? Confirm Password. And here we'll have a handle new.
And let's send this email is already in use. Is it? Clear? Let's do another one. So new
to handle is new to cool get a token.

That means we've signed up successfully and go
to authentication we have new to we go to database. And in that user new to There we
go. We have the image URL, and it's the images the no image. And if we copy that, and we
access it out, we get four or three error. And why's that? Oh, okay, I know why. It's
because we in the storage in the database access rules. By default, it doesn't allow
anything and unless we're authenticated. But we're not using the client library, we're
checking the authentication through Cloud Functions. What we can do here we can do allow,
read. So this by default will not allow right we will only allow read, which is not a problem
for us, because all the files that we're storing here are just use a profile images, which
are public anyway.

So let's do allow read publish, as published. Now, if we refresh,
there we go. We see that image. Cool. So now by default, our users have this no user image.
So let's actually test if uploading a new image works. So we have this user new two,
they have this new image. Let's log in as new two. So remove these two things and change
this login. Actually, we could just use this token, it's the same as take this token. And
on the same route, let's go to I mean, on the same tab, let's go to slash user slash
image, it's going to be a POST request. And it's going to have the header also realization
there. And we paste that token.

And here instead of a raw body, we give a form data type body.
And this key Let's name it image doesn't matter. But let's name it image. And here. Yeah, let's
change the type from text to file. And let's select the file and let's select this user
dot jpg. And let's send let's see if it's actually uploaded successfully. keeps going forever. Oh, okay. I know why.
Whoops. All right. So here at the end, where am I? Okay, we're here. So after this unfinished
event, we need to add busboy that and and we pass this request to row body, which is
a property that's in every record. object. Let's save and it runs again. And let's send
the same request. And it says image uploaded successfully status code 200. Cool. Let's
go to our new two. And there we go, we have a new image with a random name if we go to
storage.

And by the way, when you click on storage, you go here, file location, and you
take this download URL. And you go here, it gives you a URL with a token and an access
token, which you need if you don't have access permission. And if you just remove that you
hit enter, there we go, we get that image. And the same URL is stored is stored in the
database in the user's document. So which one is new to, and there we go with that URL,
we copy it, we paste it, and it's exactly the same image. Cool. And if we try to upload
another image, let's upload this PNG, sand. And it's uploaded. Someone called this image
young men instead of young man.

Nice English. Alright, so we copy that, we go here, and
we see the young man. Alright. So the image upload is working successfully. But there
is a catch here. So let's say I already created this, how convenient. So let's say we have
a text file called hello world. And for some reason, it takes ages to open a text file,
and it's got the value hello world, we can actually upload this file instead of an image,
text and we upload it as uploaded successfully. And it's actually assigned to our user image,
a text file. And if you don't believe me, if we paste it, we get hello world. That's
not very good. So what we need to do we need to handle that here. And by the way, these
are the prints we're printing. What are we printing? What is this? Oh, this is the decoded
token. Let's actually remove that.

Let's go to FB auth. And remove this print or this
console log, we save. So if you as you can see here, we're actually logged in the after
the token will login the the the name of the field, and the name of the file and the MIME
type. So when we uploaded the text, the MIME type was text slash plain. And when we uploaded
the PNG was image dot png, PNG and the JPG is exactly that. What we need to do here we
need to, if the file type is not PNG, or jpg, we don't want to allow our users to upload
GIFs or text files or whatever. So we need to do here. Let's do F, MIME type does not
equal image slash jpg. And MIME type does not equal image, oops, image slash PNG, then
here we just return an error, return res dot jpg, not just give a status code of 400, bad
request dot JSON with an error message that says wrong. file type submitted. Let's test if that's
working, we save then we go to postman with the same text file, we send.

Call, we get
wrong type, file, file type, whatever. And then if we submit the user dot jpg, it actually
uploads and it changes in our database that it changes to a JPEG. Cool, so that's image
upload. I know this has been a long video, but yeah, it's it's a little bit complex to
handle image upload. In this video, we're gonna work on adding user details. I don't
know if I've written this in a past video, but you can take a time to write or read this.
So this is our basic user basic user info. And these are extra credentials that we could
use through that we could add through our front end, a bio, a website and a location.
And of course, they're optional. So let's write a function to actually add these details.
Let's go to our index file, create a route for this. And this will be a post route. So
I've got a post. And this will point at slash user. And this will, of course be a protected
route. So let's add the middleware FB auth.

And the function will be Add User details,
which we haven't created yet. But we will in a moment. So let's import user details.
So let's go to users save this and go to users. And here Actually, I'm going to put it above
the upload image. Let's put a comment here. Add User details and exports dot add User
details, request response as per usual arrow function, let's actually put a comment on
this as well upload an image, a profile, not an a profile image for user.

Comment here
as well log us in. Now, I'm not writing a lot of comments, because that could take up
some unnecessary time you feel free to write comments as you go. But I believe in if you
write expressive code, and you name your variables properly, whenever you write clean code, you
feel like you don't need to comment as much. But of course, sometimes commenting can be
useful for other people to read your code. Okay, so let's actually write this function.
So here, we need to take a couple of details. And the thing is, I'm going to write right
now not a validation method or function, but it's, it's a function that will take the input
and make sure let's let me actually write something and then I'll explain so let say,
let us details.

The details equals, we're gonna write a name of a function that I haven't
created yet reduce user details. And this will take in the request body. And, whoops,
what did I do? Okay, semicolon right there. And let's bring in this request, reduce. Reduce
user details from validators, let's go there and create it. So and validators at the bottom
here, let's do export dot reduce user details, it will take data. And here, like we mentioned
earlier, we need, we're gonna take three things a bio, a website, and a location. So as to
let user details, initiate this as an empty object. And here, we're going to do one check,
actually, a couple of checks here, if not, is empty. And we take in the property data.
Remember that this data is request dot body. So in body, we have our properties bio, that
is the first one so data dot bio, of course, dot trim, to remove any whitespace. So if
it's if it's not empty, then user details, dot bio, equal equals data dot bio.

If it's
empty, then this will not have a bio property. So here we list do If not, is empty data dot
website, dot trim. Now here, I'm gonna do something like this tiny, clever trick, where
what I want to do is that if a user submits a website like this with HTTPS, or HTTP at
the start, so website.com, we're going to save it as
it is.

But if they don't, if they just submit website, comm, we want to add HTTP, colon
slash slash, and make sure that HTTP not HTTPS, because if a website doesn't have SSL, it
will actually crash or not load anything if you do HTTPS, but a website that does it will
still allow us to use the protocol, protocol HTTP and we can still access it. So let's
do If not, we've already done our if there is not if here, so user.

Oops, user details.
The website. Yeah, the website, actually doing it another. Yeah. Whoops, we need to check
for the HTTP. So let's do if data dot website, dot trim again, dot substring. Actually, the
S is miniscule. So substring, all lowercase. And here what we're going to do substring,
it takes a substring from a string, and you give it a start and an end. So the start would
be zero, and the end will be four. And actually, this is not a four here is actually the P
for some reason, and it's not s you would think that four would be in HTTPS, four would
be s but apparently it's not this, this function behaves in a weird manner. So if we compare
this substring to HTTP, and then so if this is true, that means the website already has
no actually this is what Compare it, we're making sure that it's not actually to be if
it's not HTTP.

That means we need to add that to the to the website. So let's do user details,
dot. Now you don't have to do this, but I think it makes it makes it more neat. So we
add HTTP, colon slash, slash. And then remember, this is a backticks. And then dollar sign
curly braces, data dot website, dot trim. All right. Now else, else, this means it has
HTTP already, we just actually, we don't need curly braces, we can just say else user details,
that website equals data website. Now for the location, it's oops, not here. So for
the location, we just say, if we're gonna do the same thing as the bio, nothing fancy.
If replaced bio here with bio, so location. What, why we're doing this is that with our
front end is definitely gonna send three properties by a website or location, even though if a
user doesn't send a bio, if they leave it empty, our, our react app is going to send
a bio property with an empty string. So our code here makes sure that we don't actually
submit a an empty string for a value of a property to our database.

If it's an empty
string, we don't even add that key. So here, we just do return user details. And this function
is done. So let's save and go back to our users file. And we've brought that in. So
where are we we're here? is odd us? Oh, boy. Okay, we're here. Sorry about that. Okay,
so here, what we're gonna do is, we're just gonna look for the document of this user.
So let's do const user document. What do we do the document? Yeah, we're actually going
to need just actually we just do.db Doc, and backticks slash users. Remember, this is a
protected route. So we have access to the to the users object. So request our user handle dot get, sorry, not get the update.

And here, it's
actually as simple as just passing this user details. Because this user details will have,
let's say, if it has bio on a value, this will just update exactly that. So it actually
works out to have an object shape like that. So here, the update returns a promise. So
then, and here, we just return a message. So let's do return res dot JSON. And the message
will say, details did successfully. And catch we have an error, which is console dot error,
error. And we return it return res dot status 500 dot Jason error code. All right, I think this is it for this function.
So let's save and test it.

Let's make make sure we we saved all files. And I've already
got Firebase running. So if we go to postman, and here change this route to just slash user,
as opposed at slash user, and yeah, I'll send and Okay, my token has expired. it expires
after an hour, so we need to log in again and get a new token. So let's login. Let's
copy that token. let's paste it here. Okay, I'll just type again, space token. Let's send
this Oh, actually, I need the body. What am I doing? Yeah, yeah, the thing is like the
other vital the validation as well, we have to have our keys. And of course, our front
end is going to make sure that we have our keys. So let's do actually an empty bio. to
test whether it's not submitting an empty key to the database. To do a website. Let's
call this user.com to test whether it's going to add HTTP to it. And let's do a location
of London, UK.

And that sound cool. It says details added successfully. Let's check our
database. So go to our app database. Go to our user, which is user right here. Cool,
we have a location. And we have a website and it's other HTTP two. And we don't have
a bio, because it's empty. Let's try to override these details. Let's say, my bio now says,
Hello, I use a whatever. And I changed the website to google.com. For some reason, I'm
the owner of Google Now. And I moved to Los Angeles, California, because why not? Let's
send details added successfully. Go to the database. And there we go. We have the new
details. google.com la, California, and, and yeah, Hello, I'm user, we have the bio now.
Okay, cool. And if we actually add the HTTP to HTTPS, colon slash slash google.com, and
we send There we go. So HTTPS, so it doesn't alter it right now.

All right. So next thing,
let's actually work this other route, because the way our application is going to work is
that we keep the login route minimal to reduce response time. So that when we log in, we
only get a token. And then when we're redirected or directed to the homepage, we use that token,
and we send the request to a different route to get all the details for our user. gonna
copy something, just to not waste time writing it from a different file. And I'm going to
paste it actually, I'm just gonna copy a part of it.

User details, and I'll explain it in
a second. So let's close this object here. So this is going to be our Redux data. This
is going to be what user information that we're going to hold in our Redux state in
our front end application. And we will use to populate our profile with, we need credentials
to show them on our profile on the right. And we need likes to actually check on the
homepage or on any page, whether any of the posts that are listed there are liked by us,
and to like show a different icon. If they are, if they're not, we just show the empty
heart icon. Alright, so we need to write the router that actually returns this data for
us. And this data will have more later when we implement notifications. But for now, we're
just going to get credentials and likes, you can take your time to write this if you want.
Alright, so let's go to index and create this route. And it's going to be an app dot get
slash user as well, it's going to be protected, because we're going to use that token to get
the data.

And it's going to be called get authenticated. user or just get authenticated
user. The names don't really matter, as long as they make sense to you, and you can remember
them it's fine. Alright, so let's import that. And let's go and create it. So in users here
underneath our user details, put a comment, get own user details. And let's do exports
dot get often dedicated user equals request response arrow function. And here, we need
to, first of all, let's declare a let rest data. Because empty object This is
the response data, we're gonna start adding data to it as we go through our promise chain.
So first thing we need to get the user so DB dot doc, slash users slash dollar sign
curly brace again, request dot user dot handle dot get dot then.

So here we're gonna get
a one document. So Doc, our function, we're gonna do a check if the document exists, just
in case because if you don't do this check is going to crash. So Doc, if doc dot exists,
if it exists, then user data, actually, is it user data? response data? Yeah, rest data.
It can be a user data, let's change it actually, to user data. It makes more sense. Now that
I thought of it like that, off the top of my head, it does make sense. Okay, so user
data credentials. Equals as simple as doc dot data.

And don't, don't forget that this
is a function. So don't take and do curly parentheses. So here, Let's now get the screams
of this user. Actually, we don't need the screens, we just need to get the likes which
don't exist right now. Okay, let's do that. I don't know if it's gonna crash the app if
it doesn't exist, but let's try. It never hurts to try something. So DB dot collection
likes where use a handle. We haven't even created this collection yet. But let's roll
with it equals request dot user dot handle. And we're not gonna order this by anything
because they don't have a created a created art. So it's just do don't get then we get data.
I'm here, we need to look through this data. So let's do data dot for each document.

We need to actually initialize user
data.so as to use the data because if we don't, it's going to crash because it doesn't know
it's gonna mess up with types. So it's actually not user data user data dot likes equals an
empty array. And here for each document, we're going to do use it data likes dot push, document
that data like this. And then when it's done, we just return the data. So when it's done
here, we do return response, or stress dot JSON. And we pass user data like this. So
of course, here, catch her the usual console, error, or return rest dot
status 500.

Jason code. All right, let's test if this is working. Let's go to postman. Make
sure you saved all your files. And here with the same token, we're gonna
send the get request and put the body as non because it's a get request with the token,
and let's hit sand. Cool, we got credentials, and we get an empty likes array. And even
though the the collection doesn't exist yet, it returns an empty array. This is how Firebase
works based on document references, it will still have a document, and it will still have
a reference even though the document doesn't exist, or the collection in this case doesn't
exist.

Cool. So we have credentials. So we have now a route to get user credentials.
Alright, so far, we only have two routes for screens, one that gets all the screens, and
one that posts a screen. Let's add a route for getting one screen and getting all the
details that are pertaining to that one screen. Alright, first of all, like these three user
routes should be grouped with the user routes like this. And let me remove this whitespace.
Let's, let's write this route. So this will be a post, of course. So up, sorry, get get
at slash. So this, this is the URL that would need the scream ID that we need to because
this is the only way of sending data through a get request is in the URL parameters. So
we'll do a slash screen slash colon slash scream ID, this colon will tell our application
that this is a route parameter. And we can access its value.

And of course, it's not
protected because we want in our application to allow users to view screams and comments
and all this stuff, even when they're not logged in like Twitter, because this is kind
of a Twitter clone. Alright, so the function will be called get scream. And let's actually,
I want to write all the other routes as a to do so that I'll so that you have an idea
of what we're going to actually be creating later. So we're going to have a route for
deleting, so delete screen, and we're going to have to do let me copy this to do so that
I have to type it again.

Like a scream oops, scream and we're gonna have another one for
unliking a screen We're gonna have a comment on screen. And I believe this is what we're
gonna do next, because it's the one that makes sense the most. All right, so we have a route
for getting one screen. But before we do that, I want to add some dummy data on Add a collection,
a comments collection, which holds exactly that. And before I add the document, I want
to copy something and paste it, I don't want to type it and waste time on it, because you
might not want to type it, I'm going to paste it right here. So these are the, our comments
are stored in our database. So they have a user handles so that we will know who submitted
this comment. And they have a scream ID. And that refers to which screen they pertain to.
So when we grab a screen, we grab it's comments by this scream ID property. And they have
a body of what the comment says. And of course, they have created add on of one they were
actually created.

Alright, I believe maybe later, they will hold an image URL as well
of their user. But but we'll see, I'm not sure yet. Alright, so let's create a comment
like this. So what we need is for things a user handle a scream, ID, a body and a created
that. So a scream, Id will get from this one screen, so copy this. And then let's create
the collection. Again, it's gonna have an auto ID a field of scream ID, that scream
ID a user a handle. We only have one user right now, or at least because I deleted the
other users a body which will say nice scream, man, exclamation marks, or ape, I suppose
makes more sense. And a creator that which will be a string. And let me copy this date.
From here, cool. Alright, so save. There we go, we have a comment that is attached to
the screen.

I mean, it's not attached, because this is a document based collection, but we
will make it so. So let's go to our screens. Actually, let's go back to index, we need
to import this, copy this get screen and add it to here. And let's save all files, go to
screens dot j s and let's create this get screen function. So exports dot get screen. Equals takes a
request the response are a function to let's declare a variable scream data.

It's an empty
object. Let's do DB dot document doc and the back backticks and do slash screams slash
dollar sign curly braces to access a variable request dot params. four parameters dot scream
Id like this. Get, of course this returns a promise. And this will hold the document.
So let's do let's do another check as well. So let's do if not doc dot exists, which is
a Boolean that that tells us whether this document exists or not. We'll hear stop and
return res dot status of 404, which stands for not found JSON with an error of the scream,
not found in case someone sends a request to slash scream slash an ID that doesn't exist
anymore. All right, so else we just add this data. Well, we don't need to do an else because
it's inferred already. So let's do screen data equals document dot data as a function.
And then now we want to add the ID of the screen to the data because we're going to
need that later.

So let's do screen data dot scream ID equals doc.id. All right, so now
we need to fetch the comments of this screen as well. So let's do return DB dot collection.
Calm comments where scream ID equals request dot params dot scream ID dot get. So this
returns a promise. So we do another one here then and we get a query snapshot because this
one Won't be this can be multiple documents. So let's initialize a safe scream data dot
comments equals an empty array. And let's do data dot for each document. Allow us to
scream data dot push, and we push doc dot data. And we don't need
the IDs of the comments.

So after here, so our comments are already there. So we just
need to return the data. So let's do return. scream. No, not not scream
data res dot Jason. No without curly braces just scream data like this because it's already
adjacent. And of course, catch and response dot status
500 dot Jason. Code. All right, I think this is it for this function. Alright, let's test
if this is working. So I'm already running Firebase serve. If you're not take the time
to run it.

And let's go to postman and test this up. Okay, so this is going to be slash
scream, slash a scream ID. And let's go to our database and grab this scream ID right
here. Paste it. And it's a get request with no headers. Even though if you have headers,
it doesn't affect it, sort of just send it and loading. internal server error, interesting.
Scream data dot push is not a function.

Oh, it's because scream data dot comments. dot
push, oops, as comments is the array of scream data is an object.
All right, let's try again. Cool, we get our data. And what we need to do though, because
right now we have only one comment. So it this problem doesn't appear. But if we'd have
multiple comments right here, it's going to sort them differently. Actually, I'm not sure
what it sorts them by. But we needed to sort them by created that because we want to show
the latest one first. So let's go here. Let me close the console. And here after we fetch
our comments, after the collection thing, and we say order, like this order. How do
you spell order by by created art, and in a descending order. So let's save and run
the query again. Well, of course, we're not going to see any difference because it's just
one comment.

And we get an internal server error. Oh, I know why. It's because Firebase,
when you have a five complex Firebase query, you need to create an index for it. But usually
it gives us a URL. But some for some reason, this URL is formatted in a very funny way.
Let's try again and see if if the the response like the console log is actually formatted
properly here. Alright, so this is the URL you're going to get as well, the URL, it says
it's going to say the query requires an index, you can create it here. So you just collect
this Ctrl Click from the console, so that opens it on the browser. And what's cool about
Firebase, the index is already ready for us to be created. However, this doesn't show
anything for some reason.

Let's go to index this again. Okay. Let's copy and paste this. All right, we'll
click Create index. And this is gonna take a couple of minutes so I'll be back on system.
Okay, now that our index has been created, we can actually send this request again and
it should show us the data And it does. And now even if we add another comment, actually,
let's add another comment just to show that it works. So let's go to our comments. And
let's do oops, no other comment. And what fields Do we have, we have a user handle the
same user, and we have a body, say another comment. And we have a creator that may copy
that date from that file, right here.

And we're going to add one day, instead of the
15th of March, it's going to be the 16th of March. And we're going to have another field
of scream ID. I'm going to copy it from here. And submit that and send the query again,
we get two comments. And the latest one is this one, we get it first. Cool. All right.
So let's create a route for actually submitting comments without having to create them on
Firebase manually. So let's go to index instead of this to do comment to let's do app dot
post, add slash scream, slash screw, colon, scream ID, screen ID slash comment. And this
will be a protected route. So let's add the auth middleware. And this will say comment,
on scream scopic comment on scream, let's go to here.
And let's go and create it.

So here at the bottom of the comment here saying, Our get
or fetch, fetch one scream. Fetch makes it makes it sound like like the code is my, you
know? Like, the code works for me, which makes more sense, because it does. Alright, exports,
I don't know, comment on screen equals request response. And here, what we need to do is
we need to validate the body, but we only have one field, so we don't create a function
for it, we just say request dot F request dot body, dot body again, because the property
is called body dot trim the equals an empty string. That means the user sent empty data.
So let's do on the same line return res dot status 400 with a JSON error, I say, comment
must not be empty. Or actually it just must not be empty, because the input will already
say comment on it.

So if we say comment, again, doesn't make sense. Otherwise, I'll do const.
Let's create this comment object that we're going to persist to our database. New comment
equals object. The body of the comment is request apps request dot body dot body. The
created art is a new date, to ISO string. The screen ID is request dot params dot scream
ID, the user handle we get from our request dot user object that's passed through our
middleware. So the handle of course. And actually, we do need to store the user image. Because
what we want to do later when we fetch the comments, we don't want to fetch the comments.
And then depending on that comment, as well fetch, depending on the user handle of the
comment as well fetch the profile image of the user.

So let's do here user image, add
something called user image. And this will be request dot user dot image URL. Now, we
haven't added this yet, but we can. So let's go to our util. What's cool about this because
we've already sent a request to the database. So we already have all the properties of the
user. so here we can just add another one called request dot Use a dot image URL equals
data dot Doc's zero dot data the function dot image URL. All right? Yeah, we're done
here. Let's go back. So here we have the user image stored with the comment. So let's persist
this. What do we do actually? Oh, we need to actually confirm that the scream exists
because this screen might not exist anymore. So let's do DB dot doc backticks slash screams,
slash dollar sign thing.

Curly braces, request dot params dot scream ID to get this screen
dot get, then Doc, because this is DB dot doc, so it has to return one document. So
let's say if not, dot dot exists. So if it doesn't exist, we return res dot status 404.
Because we don't want users submitting comments to ideas that don't exist anymore, and then
we will have to like persist comments with scream ideas that don't exist anymore.

So
we just say here, if the scrim doesn't exist, we say, screaming not found. And then if we
pass this, if and nothing happens, not not pass it as in if it's not triggered, then
we just do DB dot collection. And it will be the collection of comments. Now we add
our comments. So dot add, which I believe we haven't used yet is this is the function
that you use to add a document and you pass it a Jason. And in this case, our Jason is
already created. So we copy that and we add our new comment object.

And here we do dot
then this returns a result, I think, not actually a document reference, but we don't need it
anyway. If we come to this done blog, that means the document was created successfully.
So we just say rez, you actually need to return it res dot Jason new comment, we return our
comment back to the user, because they need to add it on the user interface. Because here
we do catch error. And console dot log. rows, rez not released event res dot status 500
JSON error code or oops, actually, what am I doing? This could
happen a lot. So we could just say error. Just say something, the classic something
went wrong. Okay, so let's save all files.

And now let's go to postman. So we have this
scream ID we do slash scream slash scream ID slash comment. And before we do that, we
need to actually log in. Let's copy all of this, open a new tab, send a POST request
with the body of type application Jason. And let's login. So email will be user@gmail.com
or whatever user you have on your database.

Password will be the password we set for we
set for it. What 404 not found, oh, oops slash login. Let's get the token. So here, still
bearer token. And by the way that a request we did earlier to get the screen was not protected
one just to prove to you. Let's send a get request without the authorization header.
We still get the screen because it's not protected.

So here slash comment, and we put the token
and in the body we have if you remember we have only one property of body. And this will
be comment. Number three. Let's send or not get post. Send. Scream not font. Really. It
makes sure I got the right ID Did scream not found? Oh, what am I doing scream
ID not screams. Okay, let's try again. Something went wrong. Let's check the error log. line
number 96 return DB dot collection. Comment, add. You comment? What's wrong with that?
Okay, so after console login, the comment that object I created, turned out that the
user image was undefined for me, you probably didn't have this error. Because the because
when I log signed up this user, I hadn't implemented the image URL logic at that time. So let's
just add image URL here. Or let me just add this and add the link to the new image. And
this should fix the problem.

Yeah, okay. So now image URL should would not be undefined
call. Because when I was trying that one, one of the keys, we had the undefined value,
which is not allowed by Firebase. All right, so the comment is submitted now, and I get
the comment back with the user image, which we'll use to display on the comment and the
front end. And if we go to our comments collection, we see that we get comment number three cool
with the user image. We're going to create two routes, one for likeness cream, and one
for unlikeness. Cream. So we got app dot post, or is it post, actually, it can be a get request
to opt out, get slash scream, slash, colon scream, ID, slash, like, or Yeah, just like,
and then it's gonna, of course, going to be a protected route, is gonna point to like,
scream.

And let's copy it, paste it again, this will be on like, and I've changed this
to unlike as well. So let's bring these two functions that we haven't created them. So
like screen. Unlike screen, one thing that I forgot to do last time. So here, where we
post a screen, we need to actually get the image of the user as well, because we don't
want to send another query to fetch it.

So we can do user image here, we store the user
image in the document of the screen. So user image equals request dot user. Remember in
the last video, we actually did this image URL thing. So request dot user the image URL
through the middleware, we're adding it. And we need to set like count initialism. So like
count is zero, and comment count is zero as well, because this post has just been created.
And when we create it, as well, as a response, we need to return it and not just return a
message. So here when we get the document back what after adding, let's do const. rest
on our response scream, I guess rest scream equals new screen. And here, let's do ress
scream dot scream ID because we want to add the ID equals doctor ID. Now you might be
thinking, whoa, this is a constant, how can you edit a key in it? But actually, you can
add a key in the constant, you just can't change the data type or the complete value
of the object. Alright, so here response to Jason, we just returned this rez scream.

And
let's quickly test that. So I already have Firebase running. Let's go to postman. We
already have a token to hope isn't expired. So slash scream. Let's keep this open. Let's
just copy this. Yeah, let's copy this here. Slash API slash scream to post the scream.
So let's copy this token. Go to headers. Authority authour. Oh boy, authorization.

Bearer space
that token I did it guys I spelled authorization properly. The body will be I don't know. Hello.
Hello. Whatever. That's And, and cool we get Hello, hello the body will
you use our images not image because this user does have an image yet, I get the scream
Id like con created. Brilliant. Okay, so that's fixed. Alright, let's create the like function.
So export, like a screen, split a comment here that says, like a scream, like a person
could not understand from like scream that it's what it does, I don't know, request response.
And here what we need to do? Actually, I want to explain something first. It's theory time.
All right, what we're going to do here, because you might be thinking, Wait, why don't we
store all the comments and the likes of each screen in the screen document itself. And
you would be right in the sense that yeah, it makes more sense to store them in the same
document. But the way databases work, you're supposed to keep each document actually really
small in size, and try to spread all the properties.

And the way Firebase in particular works is
that it, it has a maximum of four megabytes per document that Allah allows you. And of
course, if you would have a big social media website, let's say something like Twitter,
one tweet could have 1000s of likes and 1000s of comments. So it would be extremely inefficient
to store everything in one document, because it will be really slow to query that one document.
And if you needed only a few properties, instead of everything, the way how query languages
work, you need to fetch the whole document to get to get any properties. So it's more
efficient to actually spread these properties, and have the likes and the comments in different
collections and fetch them separately. I'm going to post in the description a video by
the Firebase developers themselves explaining how you structure your database like this
and why it's actually more efficient. And why it costs you less money on Firebase, remind
me if I forget to pause the video.

And by the way, I have one quick thing to say, Tell
me, please let me know in the comment section if you prefer the, you know, the just code
and let me write the code behind you. Because I just want to learn this framework approach.
Or you prefer the approach where I actually explain the stuff that I'm writing, because
I noticed I do spend quite a lot of time explaining some of the principles, but I personally think
it's better for you to understand them. But okay, run over, let me know give me I'd like
to get some feedback on that. All right, let's get to business. Let's create a collection
called likes. And the way our likes are going to work simply each like will hold a user
handle of who liked the screen. And another key scream ID of what scream they liked. Let's
grab this ID because it's the only scream I have on my database. So let's put it here.
And we could add a created art.

But it's only useful for statistics and data analytics,
because we just want to show the amount of likes, you can do it if you want, but I'm
just gonna stick to scream ID and user handle for now. So yeah, we got likes now. And that
means technically this. Actually, I have the other screen. So this screen now has one like
by this user. Let's not worry about like count for now. Actually, let's worry about it. Let's just
let's just Oh, it doesn't have it. It's okay, let's not worry about. Alright, so here, what we need to do is that
we need to check whether a live document exists or not, we can't just add like we fetch, we
query from our database.

And if this like document already exists, we need to return
a message to the user saying scream, scream already liked, you can't like it again. And
as well, we need to check whether the screen itself exists. And if it doesn't, we'll be
like, hey, the screen doesn't exist. You can't like a screen that doesn't exist. This function
is going to have a lot of code.

But it's it's good practice if you you need to take care
of the edge cases. So we're going to get both documents right now and set them in variables
because we're going to need to reference to them multiple times. And we don't want to
like type a lot of this code again. So let's do const like document equals DB dot collection
likes where the user handle of the like equals the user handle of the user that's trying
to like again, or trying to like not potentially a lot again, so request dot user dot handle
because this is protected again. That means we have access to that handle. And we chain
another word here where scream ID equals request dot params because this is the idea of the
screen will be in The URL itself, dot scream ID. All right, and let's do limit. One. Because
this is a query, that means it's going to return a couple of documents. And even by
the way, when we limit to one is still going to give us an array with one document, it's
not going to give us one document.

So let's do const. Scream document. Equals DB dot doc,
slash, screens, slash, dollar sign curly braces, request dot params dot scream, ID. All right,
let's do let's initialize that scream data equals an empty object. Do scream document.
So first check is we'll check that document that this screen document exists dot get dot
then doc. Here we do if if not doc dot exists. And return. Actually, let's start with doc
exists, because it's more efficient to start with the case that what you think is more
probable to happen. So if doc exists, then we need to actually give this scrim data this
data, so scream, data equals, we don't have to actually ensure that as an object because
it's going to become an object now, so scream data equals doc dot data, we need the scream
ID as well.

So we do scream data dot scream, ID equals doc.id. And here return like document
dot get. And here we do else that means If the document does not exist to do return res
dot status 404 JSON with an error scream not found. Alright, so after the then No, not
catch, we have another one. Because we did return like document. So this will give us
a query snapshot. So data, if so data has an empty property if if the array is empty,
so if data are empty, that means we don't have the life so we can't actually create
it. So let's do return DB dot collection. Likes, likes like this dot add. And here we
pass an object. And this object will have a scream ID of request dot params dot scream
ID and the user handle quest dot user dot handle. And the thing is, we can't do return here and
and then handle the promise in the next two then.

Because this, the problem is that even
if it's not empty, it might, it might actually go through so we're actually gonna put we're
gonna nest the than inside of this if block to avoid that problem. So we're gonna do them
scream, data, dot, like count. So we're going to increment the light count, because we liked
so we're going to increment the life count of the screen by one so we do scream data
that light count plus plus. So let's do now. So now we've already added a like to our likes
collection, what we need to do is we need to actually persist not persist, add increment
the like document, sorry, the like count in the property in the light in the document
of the scream in the database, oh boy, or ice cream, God document dot update.

And we
need to update one property, which is the like count. And we set it to scream data like
count, because remember the screen data equals the data that we got from the screen from
the database. And we've already incremented the light count here. So we just passed this
here. And and here we chain another one. And this returns a right result we don't need.
So we're here we just say return res dot Jason. So here Everything was successfully so we
return the screen data to hold the screen and Yeah, without any likes just the screen
with the new like count. So here, this f block, let's do ELS, that means we have no likes.
Rather, we have a like in this data array. That means we can't like this because it's
already liked by this user. So return res dot status 400 and dot Jason. And the URL
will say, scream, already liked.

All right, so after this, then we do catch error, res
dot status 500 error code. That's console error as well, I don't know why I'm formatting
because prettier is gonna format it anyway. Alright, let's save all of this. And let's
save this. Let's comment this because this unlike doesn't exist yet. Or let's actually
create it and just return nothing. Or do we write the whole thing? Screw it, let's write
the whole thing. So exports dot unlike, and I did say Screw it, I'm keeping it PG. Alright,
request response. const is very similar to, to like, so we can actually
copy everything. Now I know, I could do everything in one function the like that. But unlike
but the code will get too massive. And we could just add another route doesn't harm
anyone. So here we are the like document, same thing, scream document, same thing, let's
cream data.

But here instead, it's the opposite down here. So if the if the data is empty,
this is where we return the error. So let's copy this return. Let's go here and say, error,
scream, scream not liked. Because we can't unlike a scream that we haven't liked yet.
Otherwise, if we do have something in that array data array, what we need to do is we
need to delete the entry.

So let's remove all of this. Let's do DB dot collection. I
do we do that? Oh, we have the path for it. So we need to do is that DB dot collection
likes dot actually dot doc. We haven't done this yet. dB dot collection dot doc. So this
already adds the slash thing. Or maybe we can do this. Let me try something to make
it more simple. So DB dot doc, this backticks slash likes. Slash and remove this bit of
code, then we add data, the array of data zero the first member of data that actually
know what am I doing data dot Doc's zero, because this is the the array dot data, the
function.id should give us the ID. So this is the actual path for that document. And
we chain delete, which will delete the function, the document rather. And then here, we chain
them inside of this block. And then this we don't need the right result to a scream data
dot like count minus minus two decremented by one and we return scream document dot update.
Like count is scream data dot like count.

But the column here screen data dot like count.
And then as well here. And we'll say we just return a response res dot JSON. We return
actually the screen data. And here after this, then we have the catch. It's gonna have the
same error. Cool. All right, so unlike, unlike scream is done as well. So let's save everything.
Make sure you're running. Let's go to postman. So here we already have an author. And token,
because we were trying to comment now we will try to actually like slash like, and let's
not send any body and it's a get request.

So let's send this Okay, it says scream already
liked, because we added to that document. So let's actually put them side by side. So
you can see updates in real time. Let's do unlike, let's try to unlike this comment,
the screen. Okay, there's an internal server error. dB doctor delete is not function. Oh,
did to Wow. All right. Save. You probably didn't make this make this mistake. All right.
Oh, that's weird. It didn't delete the actual like, and the light count is No. Oh, it's
because the screen itself it didn't have a light count in the first place. Let's give
this a value of zero as decrementing the light count, but it's not deleting the light itself. Okay, let me have a look at this and
come back. Okay, it's actually this dB, data dot Doc's
not the data, the ID is actually stored in the document reference and not in the data
itself. My bad. Okay, let's, what we're gonna do is we're going to go to the screams. So
this what scream was it was the scream, or was the scream.

So let's put the like count
to one because that's what it was because there's only one like, and it's on that screen.
And let's send the like, again, it should say scream already liked. Cool. Let's do unlike
cool, it deletes the document. And if we go to screams, it decrements on Oh, it's this
one decrements the light count to zero. And if we send like, it increments the light count
to one. And if we go to likes, he created the like document a different like document
but with the same credentials, which is we're already here.

And this video is not that long
yet, we could keep going and created the Delete screen route. But before we do that I want
to fix something on functionality that's missing is that here when we comment on the screen,
we actually have access to the screen documents. So we could actually just increment the comment
count right here. So here instead of this return collection,
thing, let's cut this. And let's do return document, which is the scream document. And
here to use the update function, we have to add the prefix reference and use update. And
here we need to update the comment count. So let's do an object and comment count.

Who
should be equal to doc dot data? dot comment count, which is the current comment count
plus one. All right, so here, let's change a dot then to have the right result which
we don't need. And then here we paste back the adding the comment. So DB dot collection
comments, add new comment. Alright, so this should do the trick. And if we go to our database,
we see we have three comments all on this screen. So if we go to that screen, actually,
this screen doesn't even have a field comment count, because it was created too early.

So
as to comment count, and it's a number and it has three comments. So now if we submit
a comment to this, we should see this comment count increase increment by one. And of course
the comment would be created. So we have the idea right here. Let's write comment here.
Let's get a token. Well, we already had to talk about what it was take that new token.
Let's go here and how does come all the way here paste the new token. And we're here it's
comment and comment is a post route. So post In the body, a say comment number four, that
sand. And this look here. I mean, here a core common count has incremented by one. So we
have four comments now. And in our comments, we have a new one comment yet. There we go.
Comment number four. Great. Alright, so let's write the route for deleting a scream. So
in the index, let's instead of this comment, let's do app dot delete, because it's a delete
request. And it's going to point to slash scream, slash scream, colon, scream, ID, of
course, gonna be a protected route.

And the function will be delete, scream. Let's import
that. Delete screen. Save go to screams here at the bottom. Let's do a comment, delete.
I always misspell the word ScreenFlow delete for some reason. Alright, so exports dot delete
script, delete. I hate the word delete. request response. And we need a reference to it. So
const document equals dB. Doc backticks slash screams slash dollar sign curly braces request
dot params dot scream ID. Now here we do document. dot get the band get document. And here we
do if not, Doc dot exists. Well, if it doesn't exist, we say make it doesn't exist. You're
trying to delete something that's already been deleted or potentially never existed
in the first place.

So restart status 404. Jason error, the good old not found. Oh else
if it's found. What do we do here? Actually, here, we need to check. Because we need to
check that the ID, the user ID of this screen is the same as the user ID of the user decoded
from the token, because we need to make sure that this user is the actual owner of this
screen, because you can't delete someone else's screen. So we need to check doc dot data dot
user handle has to be. So if it's not equal to request the user dot handle, because we
already have that through the middleware, we need to return rest dot status 403 unauthorized
with a Jason with an error of an authorized else we're return document.
This is why we actually put it in a variable because we needed to. To use it again. Delete
oh boy misspelled delete What's happening? Then I need a button on my mouse that whenever
I click right to delete, because I don't like that word. Okay, so a message would say scream
deleted.

Yes, I did it success fully. Alright, let's catch just in case console. dot log, log or error.
Response dot status 500. json error, error code. Alright, let's test all of this. And
we're already running. So let's go to postman. And so I'm user. And this Alright, let me
make sure. So let's get the screams. So this screen is by user and I'm logged in as user.
So if I send a delete request to this scream slash, the scream ID slash delete. We should
Actually successfully deleted? Wait, do I actually we don't need this delete? Because
this can be the same. This can be like this without the extra path here or not here, here.
Where are we? Okay. Oh, we don't have to delete. Okay, my bad. I confused myself there. So
if I send this it should successfully deleted. Cool. And it does if we go to our database
that scrim is gone. Yeah, the screen is gone. If we tried to do it again, it should say
scream not found. Brilliant. I have a question for you.

How can we have a social media platform without
bombarding our users with notifications? Answer, we can't. So let's implement notifications,
I want to start by explaining something. So if we go to screens right here, you see when
we like a scream, or unlike, it's already like a bunch of requests to the database.
Now, notifications don't have to arrive instantly. So we can handle them separately. And we can
do so by taking advantage of something called database triggers. So if you go to File firestore
documentation, and you scroll down to triggers, there's a bunch of different triggers on authentication,
or real time database on an on firestore. We're interested in the firestore one. So
basically, these are kind of like events that watch changes in certain document a document.
And then on those changes, it triggers an event and it does something. So you have onCreate
on update on delete, and on right. Alright, you can read the documentation page, I'm not
gonna talk too much about the theory, let's actually implement this. First thing is we
need to have, we need to create a notification whenever someone likes a post.

Okay, a scream
is not a post, what is a post? That's not a thing. All right. So export dot create,
I'm really trying to push the idea of like a scream is like kind of an ape screams and
a bird tweets like Twitter, and this would be different. But yeah, anyway, so create
notification on like, and this would be equal to functions dot, and I'm going to change
this region function, maybe you don't have to, maybe you do. So check with your depending
on your case. So I'm going to add the region, Europe or west to, and I'm going to chain
here the namespace, firestore dot document. And the document we're interested in is in
slash likes, slash or slash, could just do likes slash, like this ID in curly braces. And here our
event is the onCreate. So whenever a document is created, and this will have a handler that
will take a snapshot and a context, for us, we don't need the context, we just need the
snapshot, which is basically a snapshot of this like document that has just been created.
So here inside of here, let's do dB.

We can't do dB, because we haven't imported it yet.
That's important. So const dB, equals require. And if you remember, this is in the util.
So dot slash on the same level, flush utils slash admin. Okay, like this. And here, we
do DB dot document. backticks slash screams, slash, we want to get the scream. Because
we need some data from the source slash scream slash snapshot, dot data. dot scream ID remember
that this is the like document, so we have access to the scream ID. So don't get returns
a promise, then this will hold a document. So here we need to, we need to add this check
if doctor exists. Now of course, it's always going to exist in this case, but it's just
good practice to add, still return.

Now inside of here, we're going to create a notification
the reason why we fetch this screen, because we need some data from it. So because we need
the the owner of the screen the handle of the owner of the screen, so let's do return
DB dot collection, or actually, db dot doc, because we know that it's going to be in the
notification. So notifications, make sure you don't misspell anything. Because they
sometimes do that you'll t snapshot.id now we're gonna give the IDE, the notification
the same idea as the like or the comment later on. And I'll show you later why this is useful.
So we do not set And inside of here, we're going to have a created art, which is going
to be new date, dot two, ISO string. And we're going to have actually let me copy and paste
this for you to use as a reference.

So let's go to dB schema. And under comments here,
I'm going to paste this. So this is what our notification is going to be like, it's going
to have a recipient, which is who's getting the notification, a sender who's sending it
a read of true or false by default, it's false, because it hasn't been read when it's created
a scream ID of which scream does pertains to a type.

In our case, we only have likes
and comments. So two types, and I created that. Alright, let's go back to our index.
So we have a recipient. And it's going to be the doc dot data of this, because doc refers
to the screen remember, dot user handle. And we have a sender. And it's gonna be the snapshot
dot data, which is the like document, the user handle. We're going to have a type. In
this case, it's a like, So type is like a read of false. Okay, this is five things,
let's check if we have covered everything 1235 we're missing? The Scream ID, curse,
go back. Scream ID is the snapshot. Or let's just do use the document can use both. So
let's do doctor ID, which is the screen call. So this returns a promise that holds a What
does it hold? Right result, I think, but it doesn't matter, we're gonna we're not gonna
need it.

So I can just leave that empty. And we could just say return. And here to do catch
error. case an error happens, we just, we don't need a block which needs to console
error. Actually, we do because we need to return. Alright, console dot error, the error
and return, we don't need to send back any response because this is a database trigger.
And it's not a an API endpoint. Let's create the next one. So here we need to do create
notification, do the same name, but we change on like to uncomment. This will be functions
dot region. Again, I may copy this, but here functions dot region. And the document will
be in comments slash ID.

And we're going to listen to on create as well. And here we're
going to have a snap shot. And inside of here, we're gonna get the scream again. So it's
kind of the same. So I'll just copy all of this. And here we get the document, we'll
check if it exists. And we create a notification with the snapshot ID, which is the comment
document ID and created the same recipient is the same, sender's the same that type is
comment. First change this to comment. The doc ID is the same, everything is the same.
Cool. So I'm going to keep going, I'm going to create all of them, and then we're going
to test them. So let's save and then underneath here, we don't have the ability to delete
comments.

So we don't have to worry about that. But we have the ability to unlike post,
actually, I'm going to put it here. So we need to because the thing is we're going to
create notifications. But if someone unlikes the post, we want to delete that notification.
I don't want to use it to have a notification for some that someone liked their post. And
then after they unlike it, they still get the notification and then they go there and
they're like what no one like that. Alright, so this is going to be called delete notification.
On on like, like this.

So it's going to be a functions. Guy. Let me copy this bit. So
functions that region a document and the event is going to be on delete a snapshot. And what we need to do here is we just need
to do DB dot doc and backticks slash What is that? Okay slash notifications slash snapshot to idea remember because the it has
the same ID the ID of the Like is the same as the ID of the notification that pertains
to that, like slabs slash snapshots slash ID dot delete.

This returns oops, this returns
a promise that holds a right result that we're not going to use. So we just leave the thing
empty. And we do return inside of her. And I do catch error, console dot error, the error,
and then return. All right, let's save. And these are DB triggers that we need to deploy
for them to work, save this, make sure you in the functions folder and let's do Firebase.
Actually, I think the command even works from the root
folder. So I don't know why I always have to go into functions. Okay, now that it's deployed, let's go to
our functions in on Firebase. As you see, we have our DB triggers. Let's go Let's copy
the endpoint and let's go here. Let's login or let's actually create a new account.

Because
why not? So sign up? Just test out just in case the functionality for adding the default
no image picture. and stuff like that Confirm Password. Same. And the handle will be Jane. All right, we
sent the post request to slash sign up. Oh, email is already in use. Let's just use
like new to. And the handle is new to send. Excuse me. All right, let's take this token.
And let me make sure that the ID is still correct. I didn't delete that screen. Okay,
so we have one screen that starts with q Ed. Yeah, the ID is correct.

Because this is a
new account. That means we have like that yet. So we'll change the endpoint to slash
like, oops, not here. And in the authentication, we do bearer, and we paste the token, and
we send a request. All right, so like count incremented to two, we should see a notification
collected, collection created and a notification created in a second. Alright, so the notification has been created.
Let's actually unlike that post, or that screen, and see if the notification is removed. And
it is removed. Alright, so let's post a comment. And see if we get a notification when we post
a comment. Let's change this to a post. And we have a raw body of type application Jason,
and we're gonna have a body of the comment will say, nice scream again, as opposed to
comment. Alright, we get nice screamer, get our comment back to us. And we should get
a notification created here. We do our get our notification and click on assess type
comment, and it has the correct recipient and sender.

The sender was new to the account
we just created and the recipient was user which is the owner or like the person that
posted the screen. Cool. So everything works. One other thing that I wanted to edit is in
the users handlers file. When we get authenticated user here, we return the user and the likes,
we need to return that their notifications as well because we need to access them and
show them on the front end. So let's add that. So here instead of returning user data, we
need to do return DB dot collection.

Notifications. Where recipient is request, use the handle
and we order by the created art date in a descending order and we limit by 10. I want
to limit to just 10 you can Not limit if you want, and then we get them. So let me make
sure I didn't misspell anything. All right, so here we chain another gun. And this will
have a data. So we'll do data dot, let's actually initialize user data, dot notifications equals
an empty array. And here we do data dot for each document. User Data dot notifications
dot push. And we actually need the notification ID as well. So what we're gonna do is, we're
going to push all the fields one by one. So let's do, what do we have? I put this on the
side, just remember what we have.

So we have recipient is doc dot data, dot recipient.
And let's copy this and paste it like 123. Okay, five more times. So we have sender,
we have created art. We have the scream ID, that type and the red. And we also need the
ID. So let's say notification. Id is doc.id. And so after this after the for each loop,
we just do rest, or return res dot Jason, use data. Let's test this out. Let's Login
as user because user right now is the only user that's got any notifications. So let's
change that to login. And let's delete these two keys and change this to user at email
calm. So we get our token, let's send a get request at slash API slash user. Actually,
we need to either deploy or, or serve I'm going to serve right now. Alright, if you
said make sure you're on localhost and not the deployed one, let's send the request.
And error nine oh, it's because we need to create an index.

So let's copy this URL. Because
it's like a complex query, and we need to create an index for it. Create index, this
will take a couple of minutes, so I'll be back once it's done. Alright, so our, our
indexes not created. So if we send this request again. And there we go, we get our credentials,
and we get our notifications as well. And if we had any likes, we would get them here,
but we don't. Cool. So this is working. Alright, there is two more routes that I want to create
for users. Before we finish off this video. Let me close this. Let's go to index dot j
s and create two routes here for users. One would be the route where we use to get a user's
details like another user's details or even our user.

So this is, say, app dot get. And
it's at slash user. Or let's say yeah, slash user slash colon handle. So this is we pass
the handle and the application gives us back the details of this user. And this is a public
route. So and we're going to call this function get user details. And one other one is app
dot post, slash notifications. And these names don't matter.
By the way, these are not front end routes. These are not what the user sees. These are
just what we send as requests for our back end. So slash notifications, and we'll call
this mark notifications. Red. Let me make sure that I spelled that correctly. Yes. Okay.
And this is of course protected.

Let's add these two and we will create them in a second.
So here and users, we have get user details, and Mark ratifications read. Alright, let's
save and let's go to users and create them. I'm going to put the get user one here. So
let's call this get another or any user There, any user users details will be exports dot
get user details. It's gonna take a request and a response. And let's initialize a C user
data cause an empty object. And here we do DB dot doc backticks slash users slash, dollar
sign curly braces to put a variable request, dot params.

Dot got. Handle? Yeah, we call
that handle. And here we do not get so we get this user, though, then we get a document.
And here we are the credentials. But of course, let's first check if the user exists. So doc
doc exists. And here we do user data dot user. equals, do we need to initialize this? No,
I don't think so. So do user that doctor data. So this is our user data. And here we do return.
Now we want to get their screams. So return. Remember, this is the Users page, we need
to see that screams. So return DB dot collection, screams and where user, as a user, user handle
the ID is a handle equals. So we have this in our request, params request dot params
dot handle. And we need to sort these as well. So order Order, order by created at descending,
we might have to create an index for this.

So get, so we're going to return it. So in
the next 10 block, we're going to have data. And here we initialize user data dot screams
as an empty array. And here we do data dot for each. And we get a document here for each
document, we need to do user data screens. Now here, we could just push the data, but
we need the ideas. Also, we need to do the screens that push and we create a new object.
So we need the body of the screen. Doctor data dot body, and let's copy this. And so
we have a created user handle a user image, like account and comment count. And here we
have scream, ID equals dog.id. So what did we say created art? Don't forget to click
Control the user handle user image? Like count, and comment count. Alright, so I think this
is Yeah, this is it, we just need their screams. Alright, so after the four H, we need to do
return risk response dot JSON user data. And here after the done we do dot catch error.
Console dot error, the error and return res dot status 500 500 dot Jason Error Error code.

Alright, so this this is sorted.
And I'm gonna serve just to start creating the I was already serving, what am I doing?
I'm going to serve and test this just for it to prompt me to create the index and then
let it index. Let it let's create and then we're going to create the mock notifications
read route what's happening. Right post requires a callback function but got an object undefined.
Oh, because we're not we haven't created this function yet.

Let's just comment this out
and try again. Of course, let me remove it as well from here because there is no export
for that. Actually When not handling if the user if
the document doesn't exist, so let's do an ls here. So if the document actually doesn't
exist, we need to return a response return response that Jason, or that status first
of 404. But Jason error, user, not found less safe, and it's gonna
serve a gun. And here, let's do a get request without any authorization header, slash API
slash user. And we get let's see, Jane, do we have Jane is found Actually, I didn't delete
the account itself.

I just deleted the entry in user stable. We have Johnny I'm pretty
sure. Oh, it's gonna give us the error for the index, I think. Can I misspelled something? status. But why would it get here? Oh, yeah. Okay,
there we go. So let's copy this and create the index. Okay, while this index is being
created, let's create the other Mark notifications read function. So exports dot Mark notifications
read. Now the way this is going to work is that when you open a sec, when you open a
drop down, that has a couple of notifications that are not red, we were going to send to
our server a an array of IDs of those notifications that the user has just seen. So we can mark
them red, so they're not marked as unread on the client side anymore.

So we're here,
we're going to need to need to do something new called a batch, right, which is in Firebase
when you need to write or update multiple documents. So let's do let's let batch equals
DB dot batch, like this as a function. And let's do request dot body. And here we're
going to have a property called. But actually, we're going to have an array as the body.
So let's do for each.

So our body is an array. And for each notification, and here, it doesn't
matter. We can call it anything but let's call it notification const. Notification equals
DB dot doc. And where slash notifications. Remember, this is backticks. So I can use
this variable notification. Yeah, notification, this one. But this is an array of ideas. But
let's so let's change this name to notification ID, here, notification ID, so it makes more
sense. So now we have this document, we need to do batch dot update. And this, I misspelled
that update.

And this is gonna take a document reference, which is the notification that
we just created there. And what we wanted to update. So the key is read. And we want
to make it true because the US has just read this. So once the four H is done, we can do
batch dot commit, oops, commit, which returns a promise, and we do then doesn't hold anything,
I think and we just return response that Jason, Jason and it's going to have a message. Also
notifications marked. For read. Write and catch. Doing it. Return response.
Yes. So let's say console. dot error, the error. Okay, so this is done, Mark notifications
red, and let's bring it back here.

So Mark notifications red
Let's uncomment this route. And what we need to do now let's, okay, so the index has been
created. So we can send this request to get the data of Johnny. And we should be able
to see the data of Johnny here. And we do cool. So we get users and we get the screams,
he doesn't have any screams, user has the screen we should see here.

Cool user has a
screen. Alright. So let's try to get so user has some notifications, right? If we go to
our database, no authentication database. So notifications, user has one notification,
let's actually add another notification for user somehow. How do we do that? Let's log
in as john, or Johnny. Let's get Johnny's handle or but or let's comment, actually,
so we can comment on john. As Johnny, we can comment on users scream. So here, we'll say
nice scream from Shawnee, and we send this post request. Yeah, nice screen from Johnny.
And we go here, find that there is a comment.

Actually, there's multiple comments on the
same post on the same screen. But we don't have Okay, now we have two notifications.
So let's take these IDs. This is why we needed to send back the ID of the notification, because
we need to use it when we want to mark it as red. So our body is going to be of type
Jason is going to have an array of strings. So the first string is going to be this ID.
And second string is going to be this ID and remember that they are false. They have false
for read. They're not read yet. So this is the second ID. And we need to send this request
at slash API slash notifications is a POST request. And we need actually john is token. Actually,
we need to use this token. All right, we send this actually slash API slash notifications
that I make a mistake. Okay, I misspelled notifications. Let's send this request. We
get notifications marked red. And if we look at our database, they have true for red. Cool.
So this is going to be the last video in right in the backend of our application, we're going
to add two more DB triggers to finish up the functionality of our server logic, or our
server less logic, I guess.

But before we do that, I want to fix a couple of things.
So let's start with users. Let's go to users dot j, s and in the signup, so here, here
in the sign up, we here at the bottom, when we return errors, here, if an a server error
happens, I want to actually return something to the client. So let's say General, not error
like general and I want to say something went wrong. Please try again, just in case this
happens, we will show it in the front end.

And one of the another thing here when we
handle our E authentication error in login, we want to we don't want to check for this
password thing. We just want to return in general wrong credentials. And by the way,
if you want, there is two status codes to error status codes, two main ones related
to login in the whoops, the auth wrong password, and the auth user not found. It's not recommended,
but you can actually use them to show on your front end that either this user doesn't exist
or it's the wrong password. But I'll stick to the safe just return like this just return.
General wrong credentials.

Please try again. But you It's up to you. What do you want to
do? Alright, so two more things in Scream dot j s, all the way up here in get all screams,
we want to get the user image of the of the post so that we can show it in the postcard.
So Doc, user image equals doc dot data dot user image. And down here in comment on screen,
when we validate the body, we want to return the error, comment must not be empty. All
right, cool.

So these are the fixes. Now, let's add our DB triggers. But actually wanted
to fix more stuff here. If you have been wondering why you've been getting these weird errors
from our DB triggers saying function returned, undefined expected promise or value. I tried
before returning zero and it doesn't work. You either return a boolean value like true
or false, or you just return a promise. So what we're going to do on our triggers is
here, for example, in Well, we're going to change all of them.

So here, when we do our
promise, here we are the return in front of it. So we return this promise. And don't worry,
just because we wrote return here doesn't mean the execution stops here, we actually
get through here. And then here, when we return this promise, we don't do another dot then
and return nothing, we just do like this. And we don't return anything when console
and or we just do that. And in delete notification, we actually do return DB dot doc, dot whatever
dot delete, and then we remove this then block. And here as well on create notification on
comment, we return DB dot doc, and we remove this block. And one thing that I wanted to fix, I noticed
that we are creating a notification on like an uncomment, even when we like our own posts,
which is obviously not a good thing. So what we need to do here, when we check if document
dot exist, we also need to check that the ID. So not the ID the handle of this, for
example of this, like is not the same with the handle of the post.

Because what this
would mean it would mean the person that liked to dispose, this is the same person that posted
this scream. So we don't want to notify them if that's the case. So what we want to do
here is, and no, not here. So if doc exists, and doc dot data, dot user handle, so this
refers to the screen does not equal snap, not spawn, snap shot, dot data dot user handle.
So this would be the like, actually, that make make sure it's user handle. So likes,
yeah, they have a user handle. So if we do this, and we would copy this, and we would
go to create notification on comment, and we do the same right here. Now we no longer
get notifications if we like our own post or our own scream or comment or our own scream.
Alright, so now I want to add two more triggers. The first one is that, what I want to do is
that if a user so for example, right now we have screams and each scream has an image
URL, user image of the user image at the time they created this screen.

While I want to
do now if the user changes their profile picture, I want to add a DB trigger that actually changes
the user image of all the screens submitted by this user to show them as well on the card.
So let's add a new new trigger here called Expo called while exports dot and we're going
to call it on user image change. And this will be a functions. For me, I'm going to
region, Europe, West one and firestore dot.

What is this going to be? I think it's Your
Honor, not on update on update. And we will the doc we're on update. We actually I forgot
to change document. So document. So we need to say first what document we want to listen
to. So slash users slash curly braces, user ID. And then we want to say on update, so
on update, and this will take a change and context. We don't need context. So we just
take change. And what's cool about this change object is that it has two properties.

So let's
actually console log them. So you see how This works. So to console log change dot before
dot data. And if we were to just copy this, and then type after here, it's exactly that
this snapshot has two values, the before it was edited, and then the after. So we can
compare these and we can see what actually changed. So what we want to do here is we
want to change the image of the the posts that this user has created.

Actually, this
is we're going to change multiple documents potentially. So we need to do a batch, not
read write a batch, right? So let's do lead batch equals DB dot batch. As a function like
this, and then here, we do return DB dot collection. Screams what whoops, what is this? What am
I doing? Okay, so where? What does it use a handle? Equal equals? What is equal actually? Yeah, change, we have the data and change
change dot doesn't matter which one we use, because we can't use we can't change the user
ID or use the handle anyway. So change dot before dot data, dot E, it's just handle in
the document of the user. And we do get and then here we get data. So data dot for each.
So for each document that this user has created.

To do const, scream equals DB dot doc backticks
slash screams, slash, dollar sign curly braces doc.id. So this is the document. And here
we do batch dot update. And we passed the document, which is scream. And our change
would be user image will now be change dot after. So this snapshot of after the change
of this user document dot data dot image, URL. Alright, so here after the forage, yeah,
we're after the forage here. So we do return batch dot commit. Yeah, that's it. So Oh,
actually, oh, we need let's, we need to only do this if the user image or the image URL
has changed, because the user can also change the, what we call them the details like the
buyer, the website and the location. And we don't want to run this batch, right? If they
didn't actually change the image. So we'll want to do here if want to do it, want to
check if change before data, dot image.

URL does not equal change dot after dot data dot
image URL. So we'll execute this only if the image URL of this user document has changed.
Let's do a console here just to make sure that it's only executing on the image changes.
And merge has changed. And yeah, I believe this is zero, we can actually test this. Yeah,
but actually, that's right, the other trigger and unless this both of them to save time,
I don't want to make this video long, because the last one was quite long.

So export that.
So for this one, what I want to do is a problem is that if we have screens, and each screen
could have likes and comments and notifications, and if a user deletes their screen, what I
want to do is that I want the trigger to delete all the notifications, the likes and the comments
that are related to that one screen that was deleted. Alright, so we'll call this expose.on
scream, scream, scream deleted. On scream delete, two functions. Let's copy this. I
don't like writing this. I still functions, functions dot region, the same document screams
scream id.com On delete, and here we gonna have a snapshot and the context.

I have an
arrow function here, we're not going to need the snapshot, we're just gonna need the context
because the context is, has the parameters that we have in the URL. So let's do const.
Scream, ID equals context, dot parents, dot, scream, your scream, Id choosing the URL.
And let's do our batch here. So const batch equals actually here, we could have made it
into a const as well, because logicals that, so batch equals DB dot batch. So function
like this, and now we do return DB dot collection.

Let's start with comments. comments. Were
the scream ID equals scream ID dot get. What is it? Yeah. Okay, so get that then. And then
we have data. Now data for each. Doc. Let's do Can we do it in one line? Yeah, batch
dot delete. And we can say DB dot doc. backticks slash comments. Slash dollar sign. doc.id.
Like this? Yeah, this is I think this is such comments slash doc.id. Yep. Now we need to
also after the forage, we need to delete as well, the likes, let's do return DB dot collection.
likes my God, where scream, ID equals scream, ID. I think we can copy this block. And then
we just paste it and what we do here, delete, slash, like slash doc.id, like this. And then
so we've looked for comments, and then deleted them.

And then we looked for likes and then
deleted them. Now we look for notifications. And then paste this oops, not this. Let's
paste this block. Yeah, so we paste this block. And so data and delete slash notification
slash this ID. And then here we just return batch dot commit, like this. And we do a catch
block, batch error. Console dot error, the error. All right, so we have to deploy because
these are DB triggers. So fire base deploy. Okay, let's test out our so what's cool about
dB triggers is that we don't have to actually just send a request, we can change stuff in
the database here on the interface, and it will trigger the DB triggers. So if we were
to go to this, okay, so this screen was submitted by user, let's change the user, the user dot
image URL right here.

Alright, so let's change this from oops, no image to no image is like
with an S, even though that this image doesn't exist, but the database knows nothing about
actual images. So let's look for change here, this should change to no images, and it does
cool. So the DB trigger is working. And if we go to functions, and to logs, we scroll
down you see this is the before, and this is the after. So this is the before and you
see here the before had no image and then after had no images.

So these are the before
and after. And here the image has changed was triggered. This, this conditional, actually
here in the F we need to do as well and else is to else return true and K Actually it goes
through this because it can go if the user just changes their details. Or if I were to
go here and change something that's not the image URL. Clear, let me open this on a different
window. So I don't keep waiting for it. So here for it to go to user and change something
else. Like, I don't know, location would be London again. And I'll do update. And if I
were to go to screens, of course, nothing changes. And I forget to go to the logs. Because
that trigger will still happen. Yeah, the trick? Oh, but I think it's because it hasn't
been deployed properly. So. Okay, let's just change something one more time. So let's change
for example, now the email the website from google.com, to Twitter.

And then if we look
here, we're still Oh, we're still getting function returned undefined because it went
through here. And this, this was not satisfied this condition. So we didn't return anything.
But with our newly deployed code, this, this problem should go away. It doesn't, or does
it? Oh, it does. Okay, so we get before we get after. So here, we changed Google to Twitter.
But image hasn't changed. So that block of code, of course, didn't get executed. Cool.
So let's test out as well as deleting our own post. So we will log in as user because
user has this scream. And then there are these notifications that are related to this screen.
So you see the ID is starting with 14. And it's this post. And here the likes are these
two likes are related to the screen, and then this comment as well as related to the screen.
So if you were to delete the screen, all these comments and likes and notifications should
be deleted.

So let's make sure that that's the case. So we log in as user. We take the
toll token. And let's do slash API slash scream, scream, slash and then we change this to a
delete request, we remove the body and let's get the ID of the screen. And we do this and
this should delete the screen it says unauthorized or because we didn't add our snap, I have
to log in again. We didn't add that token and now I don't have it in the clipboard anymore.
Sorry, guys.

I changed this to a post let's get token may put the token in the authorization
spell this correctly. Or like this authorization cool bearer token and then change this to
a delete take the ID from here to slash scream slash
that ID and that's a delete with sundered scream deleted successfully and then we go
here. So everything should be deleted from these three collections. Okay, I must have
made a mistake in the code. Okay, it says in the log it says data dot four H is not
a function. Oh, what am I doing Of course, here when we return these DB dot collection
dot whatever. Here of course we do get can't get anything without chaining get after it
just like here. Okay, it should work now. Let's save and let's deploy my bad and we need to create that that screen again
manually because it's deleted now. So let's get the ID of that screen from here. Screams are the collection is gone because
it was the only scream that screams and the ID is this Sir.

And what's gonna have a user handle? user and
a body? How this is the screen? What else we need the created art. It doesn't matter.
It could just be anything. Let's give it actually a string. I don't know just this. Give it a like count of three or two, number.
These dogmatic guys we're gonna delete anyways. Why did that one go away? So on those one,
okay, I think this is it? Yeah. Alright, we'll create it.

Let's try to delete it again, this
code has been deployed. And this time when we delete it, it should actually, the our
code should delete the notifications, the likes and the comments. So let's send this
request. Scream deleted successfully. All right, dedications,
deleted, comments deleted, and likes deleted. Sorry about that mistake, guys. One more thing,
though, if we would go to the Google firestore REST API documentation page, you could find
that this is basically a REST API that any firestore or Firebase application can use
to access their database.

So it would actually copy this endpoint right here, up to slash
documents. And we're to go to postman and paste this here. And then get our project
ID can get our project ID from our config file. So this is our project ID. Let's copy
that. So if we paste it here, and we do, let's say documents, slash screams, and send a get
request, it will actually, oh, we have no screens. Try users. Yeah, I'll actually get
our users formatted in a different way by we'll still actually get our users which is,
of course, a big No, no, it's a big security hole. So let's patch that hole. So if we were to
go to Firebase on go to database, and then go to rules. Here, because what we're doing
is we're using only the Admin SDK to access our database.

Here, instead of allow read
and write we can say allowed read and write colon, if false, which means don't allow,
read and write basically, so we're locking down a database. So now if we were to go back
to postman, and we send this request, it will say unauthorized. But if we were to send a
request at our endpoint out our API endpoint at slash screams, we will still get our screams.
Now we get an empty array, because we have no screens right now. But it's a 200, we did
get the data from the server. So yeah, this is the last thing that I wanted to add to
actually finish off the backend. So yeah, guys, we're done with the back end. And now
we will start working with the React applications.

So look forward to that. In this video, we're
going to start to create our react app. And we're going to get create react app to scaffold
all the boilerplate needed to run our application. But before we do anything, I want to show
you something. So I didn't emphasize enough the point of why we had to write all the backend
in Cloud Functions instead of using the Firebase client library. So this is basically our event
of eventual bundle our complete project bundle. And this is, by the way, a tool called source
map explorer that you can use to see which packages are have which size in your bundle.
And I'm using it to look at the final bundle of our application, which will be 457 kilobytes
in size. And as you see here, material material UI has 171 kilobytes from that. And the rest
are all necessary stuff that we need. So this is the bare minimum that you we can use to
actually have the full functionality of our application work properly.

And or should we
compare this to something like this, which is a project I've worked on before that has
very minimal functionality, actually, but uses the Firebase library Implementation Firebase
client library to actually access the Firebase database and perform operations on there.
If you notice, this package is 907. This bundle is 907 kilobytes, which is double the first
one. And Firebase alone is almost 500 kilobytes of that. And stuff like react, Redux Firebase
is 60 kilobytes. So you see how using Firebase on the client can inflate the size of the
bundle by a lot. And this is important for many, many reasons of which you can use services
that charge you with by bandwidth, like a most notably AWS s3. So you will get charged
more because your users will request bigger chunks of data. Second is if you're shipping
your single page application to slower mobile devices, they will have to unpack this massive
JavaScript bundle. And, and by the way, this project doesn't even have material UI and
and the other stuff that we're using in our project, so this will be more than one megabyte,
which is, which is kind of a lot for a react app that of this scale.

So yeah, I just wanted
to show you this quickly. Alright, so let's actually start to create our application and
the desktop here, I'm gonna open up Git Bash. And if you don't have create react app installed,
you can just Of course, you have NPM installed, I'm assuming you can just run npm install
dash g create react app, I already have it, so I can just run create react app, and then
the name of the directory will be social, a dash client. Now, this is gonna take some
time, so I'll be back once it's done. Alright, now that it's done installing, we can see
the interior. So CD, social, a dash, would we call it? client? Yeah. Okay, let me open
it in VS code by running code dot. Alright, so create react app comes ships, a, a web
pack development server that's already configured for us. So we can just run NPM start, and
it will start our app.

Let me open up here. Alright, so this is our app right now. Nothing
fancy. Let's clean up the stuff, we don't need this logo, so we can just delete the
logo. So let's delete this. Surely I need this font
family thing from here. I'm just going to delete this file, go to the app CSS, just
delete everything. But here, I'm gonna keep that font family thing just in case, the user
doesn't have the Roboto font, which is the main font that materially we will use. So
let's go to index CSS, js and remove index CSS from it. Go to App j s, remove that logo
because we deleted it. And here, I'm just gonna say I'm just gonna have a header one
that says up. Alright, let's save all files. All right, cool, are up. Let's, I want to
change the icon here and change the name of the app. I already have the icon downloaded,
but I'll post a link to this in the description.

So if you go to our app, public, we paste
it down, we delete this favorite icon thing. And let's go to public index HTML and change
fav Ico to icon dot png, or whatever you named it, I named it that and change the title here
to social ape, save, go back and everything's changed. Cool. Alright, so here in the sole
source folder, there are a couple of conventions on how to group your components, I'm going
to have two folders, one that's called pages.

For the actual pages, we're not going to have
a lot of pages, it's going to be like five of them. And here we're gonna have components.
So I'm gonna put I'm gonna create three pages for now. So home the J s and the pages I'm
going to have with lowercase with camel case, I'm going to they're going to start with a
lowercase letter basically. So I'm going to have home j s login j s, and sign up dot j
s.

Alright, so here, because remember guys I'm using es seven react Redux graph. qL React
Native snippets extension. I'm just gonna sorry for reading the whole name. I don't
know why I did that. Just gonna Do RC E. So this is a class based component and it's already
exported for us. And here I'm gonna have a header one that says homepage. Let's copy
the whole thing, go to login and change this to Ctrl, D Ctrl. D and do login. And then
paste here and then do Ctrl, D Ctrl. D, login, or lowercase login. Oops, no, this is sign
up. What am I doing? Sign up? Cool, save everything. Let's go to App j, s. And here, I already
want to install react router Dom so that we can have our different pages in different
routes. So I'm going to open up a new command line, a new terminal and say, well, it's bugged.
Okay, let's do npm install dash dash safe, React dash router dash DOM. Let's hit Enter.
And while that installs, let me create a component here. The good old navbar can't have a website
without an app bar.

Can you? Alright, so I still RC here, even though we're not going
to use it yet. And here in the home, or in the app, brother, let me close the index HTML,
the app CSS index CSS, we don't need this. So here in the app. Okay, that's done installing
let's import a couple of things from from react router DOM. So we have browser router,
you have open router, we have switch and route. Well, my OCD is telling me to sort them alphabetically.
So these are from react, router.

Dom if I can spell correctly, all right. So
for react router Dom to work, or for the router to work, we have to wrap everything here in
a router. In the route component, actually, let me name it router, because that makes
more sense. So as route, browse the router as router, and here, I'm gonna put our routes,
but we need to put a switch and not not the JavaScript switch, but the components which
close this and then put our routes here. So the first route will be the home route. And
this will be to, not to sorry, path equals slash. And this will have a component which
we haven't brought up yet. brunnen yet, of home. So this is the homepage. Let's bring
them, let's say here, pages, and let's bring our pages so import home from slash pages
slash home. Let me copy this two more times. And here, select those Ctrl D and do login
and sign up. And actually, this will be exact. So the exactly this path. So if we add something
here, it's not it's not that path, may copy this, space that two more times, and this
will be two slash login.

And the component will be login. And this will be to slash sign
up. And the component will be signed up. Alright, let's save everything. And let's see if this
is working. So we get home page here and we've typed slash we get home page. Again, slash
login should give us the login page. And it does and slash sign up, gives us the signup
page. Now obviously, we want some sort of like navigation bar here with those links.
We don't want to type them here each time. So we're going to install material UI right
now. So let's do npm install dash dash save at material, dash UI slash core. Now, you
can go to material material, dash ui.com, they have really good documentation.

And here
you can go to actually getting started and it will tell you to install it. And if you
want to link it with through HTML, not actually this is the font. And any component you want
to use, you go to component API or component demos rather. And in this case, we're going
to use the app bar, which is the navbar technically, and yeah, so you can take any of their examples,
you click on show the source and you actually get the source code and how to use these numbers.
But the way I'm going to Want to use the navbar is different to all their implementations.
So I'm actually going to do it manually right now. But there are certain things where I'm
going to copy some code, so that I don't waste time. Alright, so material wise has been installed,
let's go to nav bar. And here we need to bring it, bring a bar and a couple of other things.
So we're gonna have a lot of imports in our file.

So I want to put some comments on our
imports so that we can navigate them easily. So here I'm gonna do movie stuff, which is
material UI. So here are the cons are not constant. Because this is iOS six, by so import
our bar. From material, not actually add to material, material,
UI slash core slash bar. Now, we could actually up bar like this, now we could actually group
all our imports like this, for example, we're going to need now something called two bar
and just do this, this would work.

But this is not good practice right now, because we're
going to new need to do something called tree shaking, where we import each module alone.
Plus, the problem with doing stuff like this is that each time you run your app, it's importing
the whole framework, and it's gonna make your compiled time a bit slower. So we're actually
going to do the practice they actually recommend. So let's do a bar on here slash core slash
app bar.

And if we were to go back to the documentation page, and expand any of them,
you notice that every app bar needs a toolbar inside, and then you have your buttons inside
of that. So let's go here. And let's import the toolbar. Let me just copy this actually,
and then select this Ctrl D and do two bar, where's the bar actually is the B capital?
No, it's just toolbar like that. Okay. So here for our number one, we're gonna need
to do return like this up bar, I'm gonna want I want to have it fixed at the top.

So let's
do position fixed. And by the way, if you're wondering how I know that there is this thing
called position, here, you can just on any on any element, you can just scroll down,
and you will see the API reference, or you can go to component API and pick your component.
And if we would go to our bar here, it will show us that these are all the properties
that this component can take and the values that they take. So I'm using right now position.
And these are the values you can have.

And actually, the default value is fixed. So I
shouldn't even type that. Alright, I learned something right now. So I should just leave
it like this, because that's the default value. So let's do toolbar. And here, we wanted to
actually there's nothing right now, I'm just gonna leave it like that. And I want to put
some buttons inside. And for this, I'm going to bring in button from material UI is not
actually 100 kilobytes, this import cost extension sometimes doesn't calculate the size properly.
Okay, so here, we'll say button. And this has a property color. I'm going to do in I'm
going to give it inherit. And, and button actually can take some this is this is a can
be a higher order component, and you can pass it a component, a different component, and
then pass it the properties of those components.

And then you will have that component as a
child. So what I'm talking about, you can right now just say button, and say to what
is this, this is login. And then let's paste this two more times, and then say home. And
then this will be sign up. Let's save as go to our app. Now what we want in our application
is that we want the navbar to be at the top and then the navbar never changes. It's only
the content of the page that changes. So this navbar right here is not going to go inside
the switch it's going to be outside. Of course it's still going to be in the router, but
it's going to be right here.

See nav bar. Let's actually bring it in, say components.
And let's do import nav bar from components slash nav bar. Let's save. Let's go to our
up and there we go. We have our nav bar and we have our buttons, but the text is gone,
because it's actually behind the navbar. So let's give our, let's make this section that's
got the text a container, like a bootstrap container fusion use that before. So let's
go in the app, actually, I'm going to go to the global CSS file, app dot CSS, let's do
dot container, this class. And I want to give it so I want to give the container a margin
top so that the top content doesn't hide behind the nav bar. So actually just do margin. And
then here, let's say, so the way margin works, you can, you can give for a numbers, you can
give one or which applies to all you can give two values which apply to top and bottom and
left and right, and then you can give four, so the first one would be top, and then goes
clockwise, right bottom and then left.

So here, I'm going to do 84, top, not 2080. And
then for for right, I'm going to give the auto for bottom, I'm going to give it zero,
and then for left, I'm going to give it auto, so that it it actually stays in the middle
of by giving it auto, I'm going to give it a max width of 1200 pixels, so that it's actually
kind of pushed to the middle. Alright, so let's save that. But we need to give this
class to something. Think, what do I surround? Where do I surround, I think I'm gonna surround
the whole thing. So let's copy the cut that and then do dot container. And then put our
stuff here. Let's look here. All right, cool. Actually, the navbar shouldn't be in the container.
So the navbar should be outside, like this. All right.

But our buttons right now don't
do anything. So let's go to the navbar. Here. Like I said earlier, we can pass a component
and here we need the link component from react router DOM, the import link from react dash
router ashdon. And here we're using tree shaking as well. So we're importing only that component.
So here, let's take the link. Let's do, let's write in all of these fields. And let's do
component equals link. And here, we can actually pass the properties of the component link,
and it will be under the button.

In a way, it's like actually putting it here, but it
looks cleaner. So here, let's do so the link needs a two property. And for login, it's
going to be two slash login. For home, it's gonna be to slash to just slash. And for sign
up, it's going to be to slash sign up. So we save, and then we go to our app. And there
we go. So click on our buttons. Actually, it takes us to those pages. Cool. Let's bring
these buttons to the middle. Um, how do we let's give this toolbar a class name of nav
dash container. eyes go to our CSS, CSS, app CSS and do nav dash container which is going
to have margin auto. Let's save save everything. Let's go and there we go. Buttons are in the
middle. Cool. Alright, so our application so far has no content. I mean, there's no
markup, our pages are empty.

So let's start working on the homepage. Let's start showing,
let's fetch the screams that we have and show them here. Alright, but before we do that,
let me go to the material UI documentation. I show you something. So first thing is I
want to implement a theme. Alright, where is it? utils. No, no customization? Yeah,
themes. Okay, so we don't have to necessarily, you know, create a theme but I want to create
one. You can do so many things with the theme. You can set a color scheme you can have like,
font, your font size, your global styles, all this stuff. So I'm going to create the
theme and just set some colors. And because I don't like this blue, alright, so to do
that, let's go to our app j s. So here, we need to bring in two things. Go right here
and do import Mui theme provider from to add material dash UI slash core slash movie, not
actually stylish life styles slash Mui theme provider. Next thing is the
Create theme function.

So import, create theme, oops theme from at material UI slash course
lash styles slash create. Actually, it's create Mui theme, I may copy that and put it here.
Alright, so to create the theme, we just need to do const theme equals and we just call
that function create Mui theme. And here we pass it an object with some options. Oops. So here, we pass it this object with options.
And for me, I just want to have like a color palette theme. If you want to create yours,
you can go to hair color. And you can take any of these colors and you can scroll down
and there's a color tool here, pick your colors, you can just have the primary colors, or you
can have multiple shades. I've already got mine, I started in this text file, I'm just
gonna copy it, you can take the time to create yours, I'm just gonna paste my hair. And I'll
just save. Actually, one more thing we need to provide the more with the provider, I'm
just going to cut all of this and do Mui theme provider.

And it has a property of theme.
And it's just theme because we named this variable theme. And close that and let me
paste everything back in it. Alright, so now everything that's got the color primary will
have this main and everything that's got the color, secondary will have this main. And
this contrast text is basically the color of the text that's on this element. And for
me both colors, they have to have white text on them, which stands out the most. So let's
go to our app. And there we go, the color has changed to this beautiful blue that I
chose. Alright, so next thing, let's let's start showing the start showing the screens
here. So to do that, let's go to so the home. In the home, what I want to do is I want to
have a section here on the left four screens, and I want to have a section on the right
for the profile. And I want to have like, if you've used bootstrap before, you're going
to have a core row.

And inside of that we have columns, I want a column on the left,
that's of the width eight out of 12. And the right one would be four. And for that, we're
going to use the grid system. So the grid is basically there. So if we expand this,
you just bring in grid, which is right here from material UI, and you just put the container
with the grid and you add this container property, and then the elements will have this item
property. So let's just do that here in the home, I'm gonna, I'm going to remove this
stuff. And I'm gonna put grid container. Close this on the inside of here, I'm going to put
grid item. And this will have a property small of eight, which means of the small screens
gonna have a width of eight an x s, which is extra small of 12. So in really small screens,
it's gonna take take the full width, but I'm gonna put the text saying content.

And let
me copy this paste. And this will be for an extra small screens is going to be 12 as well.
And this is going to be profile profile like this. Let's save, we need to bring in grid
of course, or grid from material UI slash go slash that just grabbed the just grid like
this with save. Let's go back to our app. And there we go. We have this which has if
we inspect we'll have summit bring this let me put them side by side if you can see her
takes on the full width. Right now. Actually, I want to edit it because this is right now
leaving no space between them. And as you can see her you can have this property spacing.
Okay, let me look at the example the proper example. So here Yeah, the second example.
So if we look here, it's got this. Where is it? Yeah, here you give the value of the spacing
okay, right here. So grid spacing, and then you give a number. So for me, I want the number
16. So here, I'm going to say, spacing equals 16.

And a save. Let's go back. Right now if
we inspect, you're going to see that this would have a padding. Yeah, there we go. So
it's got a padding, which is going to push the content a little bit to the middle. So
there would be space between our element elements. Alright, so let's go back to our app. So here
in home, we have our, our grid here that says content. But here, we content is not enough,
obviously, we want to put our our screams. So for this, we need to fetch them from our
server. So in component that mount, I'm going to send a request to our server.
And for that, actually, we're going to use axios. So let's install that, open up a terminal
and say NPM, install dash dash save axios.

And let me go to my Firebase dashboard and
grab the, the endpoint, or the base URL of our API, I go to the project to functions.
And if you're just doing the React bit, this is going to be in the video description of
part 14, or in a comment in the first video, or in both. Alright, so I'll copy that. And
if you've done the backend, of course, you know what to do. And so in react, the way
we set up our base URL, instead of using it everywhere, we can just go to the package
JSON.

And here at the bottom, we can add a property called proxy. And let's paste this
and without the last slash, because I want to add on each request, because it makes more
sense like that. Alright, so axios is installed. So let's bring it in. So import axios from
axios. And here in the component did mount we can do axios. The get, and here we send
a request to slash screams. And if you remember, or if you've seen the backend, okay, let me
send this request. This is the type of data oops, it's a get request, and remove the body.
So this is the type of data that we're gonna get. This is one screen, it's gonna have this
these properties. So here to slash screens, because this returns a promise. So then result,
we want to do we want to store these screams in the component state. So let's initialize
that. So state state equals an object and it's got screams, and that's going to have
an initial value of naught.

So here, if we get a result successfully, we do this dot
set state. And in the state, we set the screams to because this is axios. We don't just say
response. The data is actually stored in a key called data inside the responsibility
rest data. And let's handle any potential errors. If there's any error with just console
log, error. Cool. Alright, so let's actually show our screams. Because right now we're
just fetching them. And when we get them, let's, you know, stinkers, let's just console,
log them and see res dot data.

Cool. All right. So here, content will get want to put like
a variable here, and let's call it haven't created it yet, but let's just call it because
these are the recent posts, excuse me, say recent screams, mock up. Let's create that.
So here, let's say let recent screams mock up equal. And what we want to do here is we
want to check if we have screams in the state. If the screens in the state are still no,
that means are still no, that means we're still loading the most still fetching them
from the server there. The request hasn't got a response yet. So we can use this in
a ternary operator, we can do this dot State DOT screams as a condition. That means if
it's, if it's not, no, that means we've got the data. So let's actually show the data.
So what we did here, let's do parentheses, and let's do this dot State DOT screams. So
if it's true, that means it's got some value in it, it's not not. So this set of screens
dot map, and for each screen, let's For now, let's for now returns return a paragraph and
in that paragraph, we put the opening curly braces.

And remember, this is the data we
get that show the body. So let's go back. So for each screen that shows screen, dot
body, and as you see right now we have only two screens. Alright, so for each one we show
that else if it's still no, then we'll just show a text that says loading dot, dot, dot.
All right, and we put that markup variable there. And we save, call it compile successfully,
we go to our app. And it says loading because inquire, status 404. Or there's another problem
here for material materially Why? Because of the topography, are we even using topography,
we need to add this to our theme. I've seen this error before. So we got up to our theme,
we add this property at the bottom. typography use next variance and that error should be
gone. But we're still not getting our screams because we get error 404 localhost 3000 slash
screams is not found.

Maybe we need to rerun our though server when we change the proxy,
let's let me do that. So stop it and run it again. Alright, so yeah, we had to restart
our server. And there we go, we get the text for the body text of our screams. For each
screen, we get the body text. So the first one says hello, user.

And the second one says
something. So there we go, we got them cool. Let's actually show them in a better way we
show who posted them and when and stuff like this. Now for this, we're gonna need to have
to create a component. Well, where are we in home, let me close this. And this. So here
in the home, we need to actually use a component that's specifically made to show us details
for screens. So let's create a component, let's say here screen. For screen, we pass,
we actually pass a property called screen, which is going to be the screen. And let's
close this, let's import it and then create it. So import scream from and then we're going
to put it in. So go back one level and go to components to slash scream. So let's create
this. So here let's do new file, scream. Of course, this is a component. So it's, it's
Pascal cased. So the first first letter is a capital. So as to RC e tab, remove this
export.

Now for this here, like I know we're going to do some styling later. So let's let
me show you something in the material UI material you why they prefer to use this CSS, JS type
of styling where where you actually write a write an object, a JavaScript object, and
then use a higher order component to apply those, those styles and make them into classes
and then use them. If you know, if you want to see an example of that, let's go to for
example, buttons. And as you see here, they import this with styles component or higher
order component.

And then they create a styles object. And it's optional. If you want to
bring in the theme, the global theme that you created in your app. js, you can do that.
So any stylings that are kind of shared between components, you actually write them in the
theme in app js, and then get the theme and then use them there. So you don't have to
repeat yourself in multiple components. So it's like this Your brain with styles, you
create your styles object, and then you export your component with this higher order component
with styles. So you pass it that styles and then you pass it your component. And then
this will create an object called classes in the properties of this component. And then
you get the classes and then you use it like this. So for each component, you say class
name equals classes dot button, and now these styles in the button will be applied to this
button right here. So let's let's implement that.

Okay, so let's, for now, I'm just gonna
put like some random style, just to apply this method first. So here we will have styles.
And here we're gonna have a card. So let's put here for the card, let's just say display.
Flex, which I don't think changes anything. Let's bring that with styles, but doesn't
change anything. For this example. Of course, in many cases it does. So let's do import
with styles. From Material art material, UI slash core slash style slash with styles.
And then we go here at the bottom, we do export defaults with styles, and then open parentheses
and pass the Stiles constant, this one, close parenthesis, open parentheses, and then pass
our component scream. Now, this will give us access to a variable classes and the properties.
So inside, actually inside the render, we can D structure this variable, we can say
const. Like this, when classes equals this dot props.
And of course, this is the this is the equivalent of saying const classes equals this dot, props,
dot classes, this call destructuring.

So anyway, so now we have classes, we can actually access
them. But let's create the markup of our of our screen. And each of our screams is going
to be a card. So let's look at the card element. So if we go to cards, component demos, cards,
this is the card This is one of my favorite elements in material design, it's this card
actually has these the side shadow that looks it's kind of like on top of the background,
like kind of extruded a bit. So this is what we're going to use, we're going to have an
image, but it's going to be on the left. So this is the kind of the kind of structure
that we're having, we're going to have a card with a card media, let's take some of these
imports. So namely, these four right here are these five. let's paste them up here to
see movie stuff. I spaced these, but we're not gonna need actions or action area.

To
do this. Let's do caught on like this card. And inside of card, we're gonna first thing
was gonna, we're gonna have the image. So card media. And this will have an image property.
And this will be the image of the few image of the post of the screen, it's going to be
in a variable called user image. So let's do image equals scream. Or actually, let's
just say user image, let's extract all those, those properties.

So let's do const. Or actually,
it's in the props as well. So the scream is in the props, this remember guys, the scream
that we pass here, excuse me, as in the props. so here we can, we can further destructure
properties from property from an object inside of props by doing this, so scream, like this.
And then we do colon, and then we do another object here, and then we extract properties
from inside the screen. So what we need is, we need the body. We need created art. Use
image, we need the use handle. I think this is all we need for now, maybe the scream ID.
Well, let's get all of them the light count, and then the comment, count. Alright, so this
will extract them and we're going to access them like this. So Alright, so the we have
the image. So it's there is the title property for the card, mid card media, let's say profile,
profile image. If I can spell. Alright, so after card media, we're going to have our
content. But I want to correlate or just let's just put the card content for now, let's not
worry about the styling for now.

Let's look at what it looks like and then style it. So
here we're going to have the handle of the user. So let's we're going to use this thing
called typography. In materially why it's preferable whenever you have some sort of
text that you want to show you want to use this typography object. so here if we go to
component demos, or actually it's up here. Yep, in the style, typography, typography
is any type of text you have in your app used Pog, Rafi and then you give it a different
variant, which is going to give it a different size and styling. So for this, we're going
to use typography. And by the way, whenever you're confused with these objects, you just
are with these components.

You can check them the documentation and the API component API.
And you can as well when you put they have types so when you put a component you can
press Control space in VS code, and you See all the properties or actually have an important
that so we can't see any. Okay, so let's import typography from material, UI slash core slash
typography. Now, if I press Control space, there we go, we get all the properties that
can exist on this. And then if we type, let's say one of them, which is variant, and we
do equal, and then we can get as well more properties here. For this, we're going to
use the head of five want it to be a slightly big. And let's close this and let's say the
value will be used to handle. And then after this, we want to show when
this was posted, so as to typography, variant, certain body board, give body to Okay, body
to, and let's give this a color of text secondary, which makes it a bit gray, because we don't
want it to distract from the content is just like metadata.

So this will be the created
art. Now we want the actual body of the, of the of the screen. So type biography, variant.
body, body one, let's give it body one. Let's see what this looks like. Alright, so this
is the screen. Alright, let's save. And let's save here as well. compiling, it complains
that we didn't use those variables. Let's look at our app. Alright, so there we go,
we get our card. But there's the color of the card and the color of the background are
kind of the same. So let's change that. Let's go to App CSS, and the global CSS and actually
here, the body want to give it some sort of background color.

Give it like very light
gray, RGB, going to give it to 45 to 45 to 45. Let's save. Cool, so we have not great
and these cards are white. So they stand out. Let's give this some kind of like margin.
And this should be a link to the user's page. Clear screen. Actually, this we want to give
it the component. Link. And the to oops, do not go to will be actually a template string.
So curly braces backticks. And is to slash users. We haven't created this page yet. But
let's just do slash users and then pass user handle to import link, import link from react
router, Dom slash link. Alright, let's check our app. Oh, this is underlined and the color
is still the same. Let's fix that. So here let's give the anchor tag globally. Let's
give it no text decoration. So text dash decoration, oops, decoration.

None. And to change the color, it's good to scream.
Where are we we're here. So let's change the color which is going to give it the color
primary to get the our blue color. Let's save everything. Cool. So there's not underlining
and the color is blue. We click on it. And it takes us to slash user slash Johnny. Cool.
But we don't see that image actually, because for some reason it has zero width. Can we
inspect this and try to fix this. So Oh, it's it's Oh, it's in a div. That's, that's interesting.
Let's just actually edit some styling here.

So starting with the card, I wanted to have
a margin bottom margin bottom, so that we'll have some space between the cards. Give it
20. And I think that's it for the card. Let's edit. Let's give this a class of classes dot
details. Which we don't always say content because it's the card content. And let's give
the card itself class name. classes. Remember, we have this classes object. So classes dot
card. Oh, we actually didn't give it earlier. And where's the image? Do I give the image
a class? Yes, I think so. Classes class name equals classes dot image.

We go here, let's
give image some styling. Let's give it a minimum width of 200. And, yeah, that's it. Let's
style the content. So content. Um, what do we want to do, actually? Okay, let's give
it some padding, because it's too close to the edges. Okay, feel like padding of 25.
Let's see what it looks like. Alright, so we got the image now. But I think the image
is kind of being stretched. Okay, I don't like this way, let's do object fit. No, cover the same. But I think if I were to make this
div longer, it will stretch this because we let's let's give an object fit cover because
that's a good property to give your images so that they don't get stretched by the change
the changes of the dimensions of the image.

Are let's save this. And let's look at this.
Alright, slick and much better. Of course, we need to format this because we don't want
to show this ISO time string. In the last video, we started working on the homepage,
we created a screen component. And now we're showing our recent screens on the homepage.
Now, I've went ahead and added one more screen and some likes and comments, which we can't
see right now because we're not displaying that data.

So. But I noticed something, if
you open up the console window, we have a couple of errors that we need a couple of
warnings that we need to fix. By the way, this is the data that we got back from our
API endpoint from our request. We printed it right here, here, but I'm going to remove
the print because we don't need to have the data.

Let's look at these errors. So first
one is react router Dom apparently it doesn't like it when we import link separately. So
let's fix that. So here in the screen, here, so let's do structure link from the entire
library. I think we're using it in the home as well. No. Yeah, in the navbar, we're using
a navbar. So here, let's remove the slash link and just do like this.

And by the way,
my server still run in my development server, if yours is not just run npm install, I'm
going to close this window, I'm going to save all files. Let's go back to our console window,
that error is gone. And here it says each, each child in a list should have a unique
key, or this is a react thing. I think it's in the home. Yeah, here. Whenever we are looping
through an array, and we're showing some data, each child has to have a unique key property.
So let's pass this a key property. And we know that our screams they have the scream
ID property which is unique.

So let's do scream dot scream, ID. And that error should be gone
when we save. And it is apparently I gave some class a class instead of class name cinna
card content. So that's in scream. Yeah, right here. So class name instead of class, and
all the errors should be gone. And we only get these warnings that we're not using these
values. Cool. Alright, so I want to format this, like you see in Facebook and Twitter
whenever someone posts something you see like five minutes ago, or like two days ago or
whatever. And for this, I'm going to use a library called dangerous Now we could use
moment moment is great, but moment has like loads of extra functionality that we're not
going to use.

And it's adds like more than 50 kilobytes to our bundle size. So I'm just
gonna use an old lightweight alternative code they they j s as my voice is cracking. So
npm install dash dash save day j s. And as it's installing, I'm actually gonna bring
it in here. Let's do import de j s from they j s and not the stage s. So if you forget
to go To the documentation, you'll see it's it follows the same convert or like same format
that you would use the moment you just call the class, or Lamine the library, and then
you pass it the date, like here, and then you do dot format, and you format it like
you want.

But for this one, we don't need that format we need. Actually, we need a functionality
that comes from a plugin, where's the plug in list right here. So I'm going to search
for from now Yeah, so it's this from now thing, we want to show the date like this, this relative
time plugin, so we need to bring this plugin just like this. So let's copy this. Let's
go here to import relative time from there. And the way they just works is that we need
to call this extend function to actually add this plugin. So at the start of our code we
need to do they are not in the class in the render method. So here we say they j s dot extend, and we pass it our plugin so relative
time. And here where the date is right here, we cut this created that we say day j, s,
and then we pass it the creator that date, and then we do dot from now, simple as that
we save, go to our app, I close this console, go, we get this was posted an hour ago, this
was posted 17 hour, hours ago, and this was posted 19 hours ago.

Cool. So we get the relative
time thing. Now we could keep working on the buttons that are on the card, on the screen
cards, like Like buttons, the comment and the expand and the delete button. But most
of these buttons actually depend on our authentication state. So for example, the like button, if
you are not logged in, it will, if you click it, it will direct you to the login page if
you are logged in. And if your legs if you have like the screen, it will be a full heart.
And if you haven't, it would be like an empty, just outline heart.

Now, because all this
functionality depends on authentication, that means let's actually work on authentication,
and then come back to continue with the screen cards. So let's actually implement the login
page, because there's nothing there. Alright, so let's go to login. And here, we're going
to use text fields. So let's go to the movie Doc, let me close this. Go to component demos,
we're going to use something called text field. And it's this thing right here. Well, there's
multiple implementation, but we just need a simple text field. So as you see, you just
bring in text field. And, and yeah, you just put text field inside of your form, which
form which is a standard HTML form. And you put these properties inside of it. Alright,
so let's go to our login. Let's first implement the width style or styles thing, because we're
going to need later we're going to need to bring in some global styles and access the
global theme. So let's do import with styles from material UI. Slash cause slash styles,
slash with styles.

All right, let's create a styles object for now is going to be empty.
Let's do export default, with styles, path, pass the styles. And then for the second thing,
pass login. Actually, login should be lowercase login. Again, and here we're going to have
inside the render actually, we'll do const as take our classes, or we have none right
now. But we will in a moment. So let's do equals this dot props with the destructor.
From props, let's actually use prop types. It's a good practice to use prop types, which
is a way that a built in method in react for type checking. It minimizes like the potential
errors that you can get in your application.

So as to import prop types from prop types.
And here we do login dot prop types camel case. So the first P is lower case equals
an object. And here, right now we only have this classes. So we'll say classes. And this
will be an object. So there's two prop types. Remember this prop types, capital p.object.is
required because it is required. And now we're going to have our form here. But what I want
to do is here in the login page, I want the form to be in the middle. So not to take up
the whole space.

So what I'm going to do, maybe there's a better way of doing that,
but for now, I'm just gonna have a grid, and then have three columns, and then have the
one in the middle have a hold our form. So let's bring in grid, let's do here, movie
stuff. That's important grid from material, dash UI slash go slash grid. Yeah, that's
all we need are now, here, let's remove this div, and let's do return grid, this is going
to be the container. And let's give it a class name. Even though we
haven't created it yet, say classes dot, I know this is not the form, it's the form container,
but I'm just gonna call it form for now.

Let's do three grid items. So grid item, and I'm
gonna give this a value of small for small, they will take up the whole width. And let
me copy this and paste it two more times. And then here, this one is gonna is gonna
have a, it's gonna have content, so it's gonna have a closing tag, like this. And for now,
here, let's just say I don't know, you're here, we need this form, class, say, form.
And what the form is gonna, well, I know we're gonna have a text align, we might add some
stuff more later, I still text align center, on the everything to be aligned to the center,
like the the title of the page, and we're gonna have an icon as well. Let's save this
for now.

And let's look at it. So we get yo and it's in the middle. And if we inspect
this face, if you see we have three divs. And they share exactly, like, what's cool
about material UI is I don't have to say that this is this has a width of four and four
and four. By default, if you put three elements, and you don't give any default, any width,
value, I mean, any like column width value, it will automatically split the, by the number
of you have the children you have.

So if you have four grid items, it's going to give them
25% each, if you have five, it's going to give them 20, etc, right? And I was given
them 33%. But the problem with these divs is that they don't have any padding, we need
some spacing, to push, or do we actually we don't, it's just like, because we're not going
to have other divs from this side. And this side, I'm not gonna have any content from
the left and right, so let's leave it like that.

Let's so here at the top, I want to
have the monkey image thing. Let's actually bring it from the public folder. So let's
copy this icon. png let's create a folder here called images. And let's paste it. Close
it as bring it in. Let's do import. What do we call it up icon? Doesn't matter. We can
call it anything. We go back on level you go into images.

And what does that icon dot
dot png. Cool. Here let's put image the source. What is that source? tab CRD equals? What
is it up? I can't I already forgot what I call it. Yeah, icon. And yeah, let's give
it an alternative property because react warns us if we don't let's just say I don't know,
monkey image. We'll just monkey. Close this. And under here, I'm going to have a title
that was that says typography. Actually, I noticed something here that I made a mistake
here. I forgot to fix. I imported typography and typography. And as well here I use typography
instead of typography and one of them Yeah, this one. Space this here, save.

Cool. All
right here let's bring in typography. typography from from material, cash UI slash core slash.
typography. Cool. All right here we're gonna have our title. So we're gonna do typography
and by variant of a variant of video How to one or how to to, as to how to one, it's good
for search engine optimization to have a header one in each page. And let's give this a class
name of classes.is called this page title. This is gonna say, oops, it's gonna say login
and Let's just look at it right now. Oh, it's massive, she's heard it too.

Okay, heard it
is better, let's have some padding or margin between this monkey image between I wanted
to like kind of have its own space. So let's give this a class name of classes dot image.
Let's do image, oops, image and margin, give this. So I want to give it 20 on the
top, although on the right, and then 20 at the bottom, and then auto on the right on
the left, call, there's some space between it and the title. And let's create our form
now.

So under the typography, here, let's do form. I'm going to give this no validate,
because we're going to have an email here. And by default, html5 will try to validate
the email field. And let's give it a name on submit this dot handle submit, we haven't
created yet. created, handle, handle, submit, we're gonna make it an arrow function so that
we don't have to bind to it. And it's gonna take an event. And here, we're gonna just
console log on a high for now. And here, we're gonna have our text fields. So we're bringing
in textfield, we have an a spring in has to import text field from, to material UI slash
core slash text field.

Now if we type text field, you can do Ctrl Space to see older
the stuff you can add to it, I already know I'm going to use, I'm going to give it an
ID of email, and name of email, which we're going to use later for when we are handling
the change, a type of email, which is, to be honest, not that important, but it's just
good practice, let's just add a label. The label is just gonna say, email. This is what
is written on it before we type anything. Gonna give it a class name of classes dot
txt field. This is our Java JavaScript object. So stick to like, we should stick to camel
case, variable names. I'm going to come here gonna give this a value. Actually, we haven't
declared our state yet. You're gonna give us a value of this dot State DOT, what is
this the email, the email. And here, I'm going to, there's two.

Well, there's two main ways
of handling forms in react. One is the references where you create references for your input
fields. And then you get the values that references and the second one is the more popular one
called controlled component, which is using the state. I mean, they're both the same,
I just prefer the controlled component one, so I'm going to use it. Actually, maybe they're
not the same. Maybe there's different applications for different different, you know, scenarios.
But I prefer to use the controlled component one, because we can use the React dev tools
and check out to the state to make sure that everything is working fine. So let's do this
dot state equals we're going to have an email and a password because this is our login form.
We're going to initialize them as empty strings. Actually, we're also going to have a loading
property, which is false by default. This is when when you press the login button, I
wanted to show like a spinner as it's requesting stuff from the server because we're using
Cloud Functions.

Well, in general, it's a good practice by using Cloud Functions. Sometimes
the first execution is kind of slow. It's called a cold start. So having a spinner actually
gives makes the user gives the illusion of the app being more responsive and it actually
doesn't. It seems like the time it takes loading is less when you see a spinner. Okay, so we're
gonna have an errors array in case any errors happen or invalidating the form. Okay, so
we're here. And what do we what else? Yeah, on change, which we haven't created yet. There's
gonna be this dot handle, change.

Let's create that. So we could actually do a handle change
and pass this the name of the field. But since we already have a name here, we can do it
in a, in a more generic way, by doing handle, change, equals, so I have an event. And here,
we're going to say, whatever put the handle submit outside the class. All right, so handle change is going to take an event,
and this event will have because we're here, well, or any on any other textfield, this
event will have a target property. And if we're on this text field, this target will
be this text field or the input actually in the HTML. And the input has a couple of things.
One of them is the name, because we gave it here the name and then one of them is the
value because it's what's written in it, or what's in the state. So what we can do here,
we can do this dot set state, we want to set the value of the input to the value of the,
to the to the to its corresponding value on the state.

So we can say, this dot state,
and we want to set so this is generic, it's going to take an event dot target, dot name,
so if it's if it's the email input, it's gonna have email, if it's the password input, which
we haven't created yet. It's gonna be password. and the value of this is going to be event
dot target, dot value.

All right, so this would work for both of them. And yeah, okay,
so we have this on change. And I'm going to add this full width property, which is going
to let this textfield take the full width of its containing div, I'm going to close
like this. And by the way, if you're wondering how I know this full width thing, or anything
else, you could just go to here, textfield, go at the bottom to the API reference, click
on the text field here. And you can see all the all the properties that you can actually
use this, there's tons of different stuff that you can use. To make the experience better,
we're gonna use a couple more later. But for now, let's, let's copy this text input or
text field rather. And paste it. And the second one will have the idea of password was just
actually select Email and then Ctrl D, three times or four times or three times rather,
and the password.

So yeah, I just password name is password type his password so that
we don't see when we're typing. And the label is password with capital P. class name is
that textfield values, this dot State DOT password on change is the same and, and for
width as well. Alright, so now we need a button to submit this form. And for this, we're actually
going to bring in the material UI button. So as to import import button from material UI slash core slash button. button.
Alright, so where are we we are here. So here we say button. of type Submit. And I'm going
to give it a variant. You can go to the material y, doc and go to button, not the API the demo.
Pick any variant you want, you can have the this one, I don't know what you call this
actually was the variant of this, this is the default, maybe Yeah, it's the default.
But this is called contained. So I like the content one, it has the whole color, and it
has this drop shadow, it looks cool.

Alright, so let's give a variant of content contained
the color of primary and the class name of classes dot button. And we need to create
all these styles actually. So okay, let's close this. And let's go here. Let's do what do we need to
style we need to style the the page title. So page title, I want to have like some margin
for the page title. So let's give it margin.

Still the same for same for the image. Save,
let's look at it. All right. Oh, this looks weird. Okay, so we have our inputs, but there's
too much space between the login and the images. Just reduce this to Ctrl D reduced this to
10. Let's look at, okay, this is better. Actually, I want the inputs as well to have some margin
on the top and the bottom. So let's style that. Let's do text field. Yeah, thanks to the old text field.
So I need to give the text field the margin as well.

Give it give it the same as the title. Let's
look at it. Alright, cool. I don't know what's wrong with the button. Why is it doing that?
Oh, actually, what am I saying? Of course, I know what's wrong with the button? Because
the button needs some text inside of it. Of course. Login. Yeah, there we go. Alright,
so text field. And what do we do now? We need some margin between the button and the input.
So let's do button margin, or just margin top? margin top because just say 20, you can
do a number.

And yeah, this is it. All right. Let's test this out. email@gmail.com? Oh,
of course, we didn't write the handle submit, what am I saying? Okay, we need first to prevent
default behavior. Because of course, we don't want to show this information here. And we
don't want to reload the page. So let's do let's do event, dot prevent default. And here,
what we want to do is we want to send a request to our server, and then show any errors or,
or if it's successful redirect to the homepage.

So we're going to use axios. So let's bring
it URL. So let's do import axios, from axios. And here, what we need to do, well, actually,
we need to implement the loading thing as well. So once the this so the form is submitted,
we do this dot set state. Two, and then we give loading, true. And then once everything
is done, we're gonna set it back to false. And now we're going to do axios dot post.
And it's gonna be at slash login. And by the way, if you if you haven't, if you don't know,
or if you haven't forgot, or if you haven't seen the part for the API, this is how the
login works. You send an email and a password.

And if it's wrong, you like, if the email
is wrong, you get an error. Actually, if anything is wrong, get the general error that wrong
credentials, please try again. And if if the email is empty, you get an error just for
the email. So we're going to use this errors object and give just that input the error
that corresponds to it. And if it's, it's like, if it's correct, we get a token. When
we get Oh, user, not users. Yeah, so if it's correct, we get a token, of course, an OK
response, which will allow us to redirect to our homepage.

So here, so post that login,
let's get the data so const user user data, let's call it and it's going to be an object.
And this will be will have a an email, this will be this dot state. So remember, we bound
those values to our state, this dot State DOT email, and the password will be this dot
State DOT password. And then we pass user data here, I mean, we could put this object
here but it looks cleaner like this. And this returns a promise. So then if we get a result
so if we get here that means we're successful. So let's actually console log our result.
Result Oh, this is axial. So with the data will be in resultant data. So first successful
we want to redirect so want to do all a set the loading to false actually, first, let's
do this dot set state. Loading to false. And then here we do this stop props dot history
dot push and then This is a, this is a method we use in react to, to push state URL and
then we go to it, or a path.

So here we push slash, which is the homepage. So this should
redirect us to the home page. And but if we have any problem if we have any errors, so
we do catch error, and here, we need to set the errors of our form. So what we need to
do is this dot set state. And we want to give the errors, the value
of error dot response dot data. And we want to, actually, this is errors. And we want
to set the loading to false. Right now the loading is not being used by anything.

Let's
get the loading from from the state. That's actually good errors as well. So we can display
them. So let's get errors. And loading from state. This dot state is in the structure
and again, and here for the input, we're gonna use something called helper text. So if you
if you click on an input, actually not here, so if we go to text field, yeah, this is the
helper text, this text right here, and you can use it to display arrows, or you can use
it to display hints.

We're going to use it to display errors if there's any. So here
what we need to do, we need to say, helper, oops, helper text equals, and this will be
because this is the email this will be errors dot email. And we don't have to worry about
if there is nothing errors, if there is no emails, if email property is just not going
to show anything. And here as well, we need to have an error property, which sets the
field to be read. So here we say error. And the way we determine whether we have an error
or not, is because we this is the email we say errors dot email, and use a ternary operator.
So that means if we do have this key, that means there's an error in the email because
we have received an email key in the errors array.

Object. So we say true, else. It's
false. There's no error. Otherwise, if we don't have this, so let's copy this and give
it to the password as well. So here, let's do errors dot password, Ctrl D, and the password
like this. So now when we get our response, and we get errors like this, or is it errors
like this? Let me cause an error to happen. Actually, no, I mean, how this empty. We can
have this email and we can show it in the helper text. All right, so let's save. So
let's leave them empty. And we click Login. Oops, it says, type error cannot find data.
Oh, it's because I misspelled response.

Response. All right, so we sent there we go, we get
our errors and put in the helper text and the input is invalidated. And if I would put
an email here, so let's say I don't know, like something at something. Whenever I type
something random, it's like sad what the hell. Alright, so login, that error is gone. And
if I give like a random password, Oh, actually, we need to show if the credentials are wrong,
we need to show some error right here. So So here, I show it under the button, or not
actually show on top of the button. And let's say here, we do like a conditional errors
dot, because if we have wrong credentials, we get we get an error called general.

So
let's check for that error lead to errors dot general. So if it's the case, so and and
if we have errors dot general then render this understood typography variant, give this
body to this we'll have a class name. Because we want to change the style of this classes
dot custom error, I'm going to call it and here we're going to have the value of that
general key.

So we do errors. dot Gen. And here let's, let's get discus. Let's style
this. Let's Okay, so custom error. Let's give it a, like a red color color. Red like this.
And let's give it like a smaller font size, font size. Let's give it like naught point
eight, run. Yeah, I think that's it. Okay, let's try some wrong email. And some wrong
password. Cool. We got wrong credentials, please try again. Let's
give it some margin. So it's not too close to the to the input. So let's give it margin
top, say 10 pixels, like this, or just 10 like this. Oh, I mean, I have to put something.
Yeah, there we go.

Much better. Let's as well add some text here that says, if you don't
have an account, go to sign up. And with a link that redirects to sign up. Let's go here
under the button. Let's say give us put a small and say don't have an account. Sign
up. And then put a link here to slash sign up. This is the React router Dom
link. And it will say here. So this will the word here will be a link. So let's go and
bring in link. Import link. Whoops link from react router. Dom. All right. Oh, actually,
as well, I want to do something I want when we click Oh, this is not cool.

So I want when
we click on login, I want to show a spinner inside of the inside of the login button.
And I want to make it this disabled. So we don't we can't click it again. Alright, let's
make this actually come down. Like under the button. Let's just add a line break. So.

Yep.
All right. It's cool. So if you click here, it goes to the signup page, which has nothing
right now. Alright. By the way, this looks purple because it's visited you can change
the color of that. I'll add the login the spinner thing you can go here. Yeah, progress
is progress thing, we can add the indeterminate progress one. So which is just what is it?
It's circular progress, we can copy this. Let's go here. On the movie stuff. Let's bring
it in. And here it's gonna be inside the login button. So here let's do if loading. So if
we're loading we do we return this circular progress thing. And let's do a class name.
Because it's gonna need some styling classes dot progress. Now, the way I want to do it,
I want to have it in the center of the button. So I'm going to do to the button is okay there
we give class progress. Okay. So so the button will have a position of relative so that we
can give the spinner a position of absolute so that we can put it in the middle.

So position.
position. Absolute. All right. Okay, we've got a spinner for like a fraction
of a second sexually. Why is it being too fast on it to be slow. So let's give the wrong
password lesson as being too fast, but all spinner is a bit too big. To give it can take actually a size property.
Just just a number. Let's give it a size of 20 or 3030s. Okay. I don't know I can't see
it right now. But we get a spinner back. Oh, actually, it's, it's in the middle. Let's
go. That's fine. What do we do? Actually, I want to I want to make the button disabled
when we're logged in We are loading. So we will do disabled, which is a Boolean, and
we just pass that loading. So if it's loading, it's disabled, if not, it's not disabled.
So let's refresh, hit the login button, see becomes like disabled for a second.

Cool.
And if we have the correct credentials, so email us@gmail.com, we get 123456, the password,
cool, we're redirected the homepage. And, of course, we're not setting the state to
be authenticated or anything, we're just redirecting right now. So in this video, we're gonna create
the signup form. But before I get to that, I want to recommend you guys download the
React developer tools, Chrome extension, I'm assuming you're using Chrome if not find an
equivalent in your browser, it's really helpful. If I open up my developer tools, put them
side by side, open up the React tab, you can see we can drill in all our components and
see what's happening, what components we have, what state they hold. For example, if we click
on our login component, you see the state right here. And if we type stuff updates,
you see update live, if we get some errors, you can see our errors. Here, you can see
the loading Boolean, you can even trigger change values and see how your front end reacts
to it, you see, I can put the loading and I can see that animation.

Alright, so it's
just that one, one thing I recommend you guys do. Alright, let's actually create the signup
form, it's actually gonna be so similar to the login form. So let's go to login, copy
everything from here, and then go to sign up. Let me close the terminal, paste everything.
And we're going to change a couple of things. So first thing, first thing, these styles
are shared between the two components, so we can make them global. So let's copy everything
here. Let's go to App j s. And here, we can paste them in our theme. And we can get them
by making the styles actually a function that takes the theme object and returns the following.
And here, we can just spread the theme. And we will have access to everything that's in
the global theme. So let's do the same for login actually.

So let's go to login. And
here instead of styles, we'll just do styles like this. And we're going to have the theme
in there. Cool. So now here, let's change a couple things. So the class is sign up.
And here we have an email and password. And we have a Confirm Password. And we have a
handle as well. Alright, so that's the same, this is the same here, we have new user data.
And we also send the Confirm Password. This dot State DOT Confirm Password, and the handle
as well.

So this dot State DOT handle. All right, so here we send an axios request post
request to slash sign up. And we send the new user data. One thing I forgot though,
when we get the token, in res dot data dot token, we need to actually store it in local
storage so that if our application somewhere refreshes the page or closes the browser opens
it again will have access to the token locally. So we can do local storage dot set item. I'm
going to call this FB for Firebase ID token like this. And the value will be a template
string bearer space. And here we do dollar sign curly braces res dot data dot token.
And we need to do the same for login actually. Let's copy this one line and go to login.
And here when we get a response, we do the same. Alright, so let's go back to sign up.
Okay, so we set the state to load loading to false we push to the homepage, everything
is the same, we get classes.

And here the title will be sign up. Excuse me. Here the first text field is the
same as the email the second one is the password is the same. And here we need two more text
fields. So let's copy this and paste it. The third one will have the ID of Confirm Password
we're not really using these IDs but it's if you want to use them to style or anything
you can or to do anything else. The name will be confirmed password like this and the type
will be password the same the label will be confirmed password like this. Class Name is
the same the error will be error dot Confirm Password. Same thing here and here. Starts
data Confirm Password and handle changes the same.

The third one, the fourth one, rather
will be handled. The type is text, the name is handle the ID, the label is handle with
a capital H. And here the errors errors dot handle. So we can do Ctrl, D twice and right
handle the rest of the same. And here the button should say sign up. And here we should
say, already have an account on which should say login here. And this will redirect to
slash login. And this will be let's do control D here as well. So you can we can change both
of these and do sign up dot prop types equals classes is an object and is required. Alright,
I think this should be fun. So let's save all files. I've already got the server running
the dev server up and running. So if we go to our app, we go to sign up, we see this
phone call, we send we got our errors.

And we actually if we actually like do new three,
et CIE email.com. And the password will be 123456. And we let's do a handle that exists,
it's going to check you will see that let's do a new three with sign up. Cool, so works,
redirects, everything is fine. These are just the requests that we send, and we're not valid.
So that's fine, we go to application for local local storage, we find that our token is now
stored.

Alright, that's cool. One thing though, if we refresh, actually not not for refresh,
if we go to the login now or the signup, it still lets us through, even though we're logged
in. So let's let's implement something that prevents this behavior. So let's go to here
in app j, s, actually, let's move all of this because I don't want to scroll this much here.
Let's move all of that object. And let's create. Let's create a folder here called util for
utility. And let's create a file in there called theme dot j s. And inside of here,
we'll say export default. And we just export this, this theme. So this object, let's save.
And here, let's bring it in, let's say import theme, or there is a theme. So let's say theme
file from go back one, we're on the same level slash utils. Slash theme, since it's the default
export, we can name it anything and here we just pass it to the Create Mui theme, and
the behavior should still stay the same. And here, what we want to do is that once this
code that's here executes one once the application is started.

So what we want to do, we want
to get to the token. So let's do const token equals we can do local storage dot get item.
For actually we could just local storage is an object, we could just access this property,
so local storage.fb ID token. So we get this property. And we do if token. So if we don't
have a token, this will be undefined. So this condition would be false. So here, what we
do is, if we have a token, what we want to do is we want to get this token decoded. And
inside of the decoded token, we have an expiry date. And actually to decode the token, we
need to install a library. Let's do npm install dash dash save j wt dash decode library that
decodes JSON Web tokens.

I know this is a Firebase ID token. But essentially, it's a still a JSON web token.
So let's bring that and let's do import j, wt decode like this camel case, from J WT.
Well, you can name it anything but just don't. Whatever you name it here, you name it, where
you use it just to avoid any errors. So here, let's do const decoded, token equals j, wt
decode. And we pass it our token. And now this will have a property called ESP. And
if you were to go to the dev tools to the console, you'll see we have this token. Actually,
we can't decode it here. But let's do console dot log decoded token. And here, it will find
the token it will console log this decoded token and it's got this ESP value whereas
it is right here.

pexels photo 6483581

So this is a time value. That's like a time from epoch. It's gold.
So if you new date, and you pass it this. Actually this is in second, so we need to
pass it this times 1000, you get exactly when this token is going to expire. Alright, so
what we need to do now is we need to compare it with, with now actually, so as the if decoded
the code ID token dot x p times 1000 is less than date dot now as a function, that means
it's actually expired. So we need to redirect to the homepage or to the login page. So we
do window dot location, dot h ref equals slash login. And actually, let's do a, let's do
let us do a property a global variable called authenticated, and it has no value initially.
So here if it's expired, we say authenticated equals false. Now else if it's not expired,
authenticated, equals true. And now here, for our routes for the login and signup, we
want to do something where we check that if we're for authenticated, we redirect to the
home page.

So here, let's actually instead of this route, let's control D on this type
of route. Let's create this component. Let's bring it in and then create it. So let's do
import auth. Route. And you'll see what this author does in a minute. Components slash,
actually, this will be in util. utils, slash auth. Route. And then utils, let's create
an Krishna we put it in neutral or let's put it in utility utility. And we're not going
to use it, it's not a markup component. So orthros.js. And here, let's do it's going
to be a functional components.

So RFC tab, I'm going to change the syntax to const. Off
route equals props, and then gives us the following. And let's do export default, off
route. Actually, let me destructor straightaway what we need from it. So we're going to pass
it a component. So from the component, I'm going to get the component with capital C
naught, capital C, which is going to hold the component that we passed it. And here
we're going to get authenticated, the property authenticated. And we're going to spread the
rest of the properties. So if we add anything, it's going to be added here. So here what
we return, actually, we can change this syntax to just parentheses so it straight away return
something. And here we need the route from react router DOM.

And re direct react router DOM. Riley, close
that. And here we do route. And we spread the props that the rest props. So rest, and
here, we're going to trigger a render method. And so take the props. And it's going to check for authenticated.
So if authenticated equals true equals true. Then we run a redirect redirect. And this
is so forth indicated, we redirect to slash, which is the home and we close this, else,
we just give that component which is going to be either the login route or the signup
route.

Now props, let's spread the spread the props here, I mean, not arrest. Alright,
this should be fine. We need to close the route toggle or route component and let's
save. Alright, so one more thing though. Here, we actually pass it authenticated. So click
here and hold Alt and click here and do authenticated equals authenticated. Alright, let's save
this. Let's go to our app. Let's make sure we have a token and it's not expired. So if
we go to login, cool, it redirects us back to the homepage. And if we actually if we
delete the token, now, it's not going to redirect us to the homepage. Because this doesn't execute
again, only executes once the app runs. But when we implement Redux later, it's going
to fix it. So now we Don't have a token, if I refresh the entire page, if I go to login
and sign up there, we're gonna work fine. But yeah, once we implement Redux, and we're
going to have like a global state and is going to update each time we do something, it's
going to this we're going to behave much better.

As our application grows bigger, and we will
have more components and all these components, or most of these components will need to have
access to the data we have on to our user, it would be better that we would implement
a solution that manages a global state for our application. There are a lot of situations
where something called context API, which comes shipped with react is actually better
than Redux. You can look into that if you want. But for this application, it's better
to use Redux. And to use Redux, we're going to need to install a couple of packages.

And
if you don't know what Redux is about, I will post a link to this really cool article that
I think you should read to understand what Redux is and why we use it. It will introduce
you to concepts like a prop drilling like and funnily enough, it uses an example that's
like what we're making right now, which is the social media platform that's similar to
Twitter. So if you look here, you will see that it becomes a problem. For example, in
here, if we wanted to have the user in this avatar component, we have, we'd have to pass
it from the app to this avatar, and then down or down this chain of or rather hierarchy
of components.

So it becomes really inefficient, and it becomes really ugly code. So what we
need to do instead would have something set up like this, where we would have a store,
and whatever component no matter how deep or down in the tree it is, it can directly
talk to the store, fetch data or send actions that will tell our reducers to mutate our,
our global state and change it so that all the other components will be aware of these
changes that are happening. Now there's a really cool diagram that I want to show you in this article,
which I will link a description, link in the description as well. But funnily enough, I
don't want you to read this article.

Because I don't know this guy I feel like is trying
to use too many like buzzwords and fancy language and try referencing other libraries that maybe
you're not even aware, like aware of. But I just wanted to focus on this diagram, because
it kind of encapsulates what react is, essentially, we have events triggered from our UI, or user
interface, like someone clicking a button submitting a form, whatever any of these actions
could trigger an event, and then an event will fire up an action. And this action will
dispatch an action with a type and sometimes with a payload as well. And then that type
gets received by the reducer.

And the reducer will then decide depending on the type of
received, what to do, and how to mutate our state. And then once the state has changed,
all of our obligation is aware of the state. Now, this might not make sense right now to
you. But once we get into the code, trust me, it will make sense. One thing you need
to install if you don't have it already, if you're using I'm assuming you're using Chrome
if you're not, then do or use Firefox is cool as well.

But I don't know if they have Redux
dev tools on Firefox, you can install Redux dev tools as a Chrome extension, which will
help drastically actually this is one of the reasons why I prefer always prefer Redux over
context API, because of this dev tool makes, makes our lives much more convenient. Alright,
enough of the chitchat and enough of the theory, let's actually start to implement Redux. Okay, so let's go to our app. I'm going to
open up a new terminal, and we're going to install three packages. So NPM, install dash
dash safe. First is Redux, which is a standalone JavaScript thing. Second is react Redux. And
third is Redux thunk. So react Redux is the library that kind of is the middle middleman
between Redux and react. And Redux thunk is a piece of middleware that gives us access
to something called dispatch, which allows us to run asynchronous code in in our Redux
actions, is something that you shouldn't worry yourself too much about right now, to be honest.
Alright, so in the source, I'm going to create a folder called Redux.

I like to keep everything
related to Redux inside one folder, and here we're going to create two folders reducers
and actions. I'm going to create two files, one called store dot j s, and one called types
dot j s. Alright, so here in the store. Our store is basically what contains The container
of this state. So here we're gonna bring in a couple of things from Redux. So let's do
like this from Redux. And here we need create store to create our store, we need combine
reducers, which is something when we because we can have all our reduced, you know, reducers
in one file, but it doesn't look good. So we we split them into a couple of files, and
we will use this to combine them, we'll have apply middleware, which does exactly that.
And we will have something called compose. And I'll tell you in a second, why we need
that. So we need to bring in funk, which is a piece of middleware or, or store enhancers,
well, you can call them that as well.

And here, we need to initialize an issue, an initial
state, which is going to be just an empty object.
And here, we're going to have an array of middleware, just going to have thunk, actually, you can
use other middleware, you can create your own depending on what use case you have. And
here, we're going to have our reducers, which we actually create, I'm going to create three
files, but I'm not going to write anything in them right now.

Data reducer dot j s, which
is going to handle every all the actions related to our data, going to have root user reducer
dot j, s. And we're going to have UI reducer dot j s. And here in the actions, well, might as well
create them now. So data actions, dot j, s. And what's the other one user actions? dot
j s, and we're not going to have a UI actions because we're going to fire those from both
the user and the data actions. So here we do because reducers Actually, we need to import
them import first as user reducer, in no particular order, calls input.

What am I doing from this
is not as five from slash reducers slash user reducer, I'm just gonna copy this, paste it
two more times. And here, I'm going to say Ctrl, D, and do data reducer. And here, I'm
going to do UI, reducer, whoops, reducer. And here, we're going to combine them. So
reducers equals, combine reducers. And if this code is a bit confusing to you don't
don't make it confusing, because this is just one thing you're going to write once, and
then you're going to do the actual code inside the actions themselves. Alright, here, this
is our actual state. And here, we get to name our objects inside the state. And for the
user data, I'm just going to name it user and give it the user reducer. So everything
that comes from the user reducer will be stored inside of this user object. It's not Yeah,
inside the user object inside our state, we're going to have data.

And this is going to be
from data reducer. And we're going to have UI from UI reducer. Now we can create our
store. So we do const. Store equals create store. And here, we pass it through things
are reducers. And the second is our initial state. And the third will be usually it would
be just the middleware. But if we were to go to our application, and we do have 12.
And we go to the Redux extension. I don't know why it's saying that we have a store,
we don't actually have a store. But to have like, let's look at the Redux Dev Tools set
up because there's this, this long string that that we need to put here, this one right
here. So window dot Redux dev tool extension, we need to apply it as a store reducer. So
that we can, so that we can see the data shown on that on that. Extension, so apply middleware.
And here we spread our array of middleware, so dot dot, dot middleware, and then the second
argument to compose we actually paste that the string we copied from From the React Dev
Tools GitHub page, so we save and it formats.

Let me close these console windows. Yes. Okay,
so this is our store, we actually need to export it. So let's do export default store.
So this is basically what contains our application state. Now we need to actually give it to
our application. So we can do this by going to App dot j, s. And here we're going to bring
two things. Let's say Redux. Here, we need to bring something
called provider from react, Redux.

And what do we need, we need our store. So store from one level, or on the same level rather, Redux
slash store? Yeah, we just need these two things. And we need to wrap all of our application
inside of this provider. And it doesn't matter, it can wrap the movie provider or the movie
provider can wrap it, it doesn't matter. They don't interact with each other. So we can
just put this provider and it takes a store, which is going to be our store, we close this.
Now let's cut everything and put it inside of this provider.

So now, as you can see,
everything that's inside of this provider will have access to our store, which is our
state. And by the way, we can remove this div up, because it's not stealing anything.
It's not doing anything, actually, that's safe. Okay, right now, we just introduced
Redux, but we don't have anything. And if we would go to our application, and refresh,
my dev server still running. If we go to Redux here in our state, actually, we haven't initialized
that. Okay, so now what we need to do is that we need to go to our data actions. Rather
user actions, let me close everything, user actions, because what we're going to start
to do is we're going to start to move this code or this login code from the login component
and the same from the signup component, and move them into the user actions. So here in
user actions, I'm going to actually Before that, we need to create some types.

Now, you
don't have to create types, these types can be just strings, but the fact that we create
them and put them into variables, it makes it impossible for us to make a mistake, because
we can actually pass because if we make a mistake, name and a variable, it's not going
to run so that it makes it easier to spot our mistakes. So let's do export const. And
here, I'm gonna create a couple of types. First one will be set, authenticated. Thumb
to cated, which equals actually exactly that, but as a string. You also need oops, a type
for set. And it's, it's just a convention that we named them in all caps, set unauthenticated,
which is going to be the same as a string. So paste it here. And we need also a set user
type called set user. What else we need a tie. Now we're not going
to use all of them in this video, but I just know that we're going to need them later.
We need a loading user. She's gonna be just that. We actually
let's, let's put a comment here, say user use reducer types.

And here we say UI reducer
types. And we're also going to have data reduce types. And here for the UI reducer, we're
gonna need export const set errors. I'm gonna just copy this. We're gonna need what else
loading Ui Ui like this UI clear errors. I think this is it for now, if we need any more
types, we're gonna create them. So let's go to user actions. And let's bring in as bringing
these types that we need for user. So set user, we need set errors. We need clear errors,
and we need loading UI. Ui from go back one level and go to types. And
here, we're gonna actually just move this code that's inside of the handle Submit. So
the login code, so let's copy, actually, from here, this axios call, and let's paste it
into, let's call this action, export const login user. And it will take user user data.
And here, it's gonna, we're gonna as well get this batch. Because here we need to access,
we need to use the special because we have some asynchronous code.

And so we paste that
code in. But actually, here, we need to set the loading to true. Actually, we can remove
the loading code from login, and we can even remove it from the state. So we can set the
login from the action itself. So here, what we need to do is we need to say this batch.
And this is where we actually send an action. So this action is going to have a type. And
this type will be loading UI, you can start to see how this works. We dispatch a type.
And then we will catch the type from the reducer.

So let's actually just check if this code
is sound. So we log in, and then when we get the data back, okay, so here, when we get
the data back, we want to, we want to actually fetch the user, I'm going to create a new
account, I'm going to create a new action that we for some functionality that we didn't
even have in the last video, and it's going to call this get user data. And it's not going
to have any, it's not going to take any argument because it's going to use the token that we
got back. And it's going to use this batch. Actually, before I do that, now we get the
token. So if we get here, that means we have the token in res dot data dot token. So what
we need to do, we not only need to set it in the local storage, but now each request
that we need to send to a protected route, we need to add the authorization header.

But
it wouldn't be efficient for us to each time we send the request, we add we add it there,
we can take advantage of this axios axios, default headers thing. And we can do axios
dot default, dot headers, dot common. And by the way, this is in axios GitHub documentation
page. And here, the header will be authorization. and the value of it will be the actual token
that we got plus bearer so we can do bearer.

I should put this in a variable. So we can
say const, FB ID token equals template, string bearer and space and then we do res dot data
dot token. So now we can give this variable here. And we can as well assign it here to
the headers. So now when we do this, each time we send a request through axios, it's
gonna have a header, an authorization header with this value even to not unprotected routes,
which is not a problem at all. So here in get user data, we can just say axios dot get.
And if you remember, we can send a get request to slash user, which will get us the user
data.

So here we do dot then recce. So if we get a result success result, we need to
dispatch an action. So here we dispatch an action of type. And this type will be set
user. And this action actually takes a payload. And a payload is basically some data that
we send to our reducer, and then the reducer does something with it. And the data here
would be just response to data which we get back which is the user data. And of course,
we need to handle in case there's an error. Catch. And if we get an error here, we just
console logger console dot log error. All right. So We get the user data when we log
in. And here what we need to do when we get the data. So there is no state because we're
not in the component. And we don't log it. So here, what we need to do is we need to
dispatch, the get user action, we can actually just do this after all of this, we can just
actually just do this batch.

And we can dispatch this function that's right here. So we say,
Get user data. And it's going to call this and thing is Oh,
actually, we need to redirect. So what we need to do, actually, we need to pass. So
here, when actually, we need to pass the history from this component to the action, and then
the action will use it. So we can put it as a second parameter here, let's call it history.
And here, we just do history dot push, and it will actually work it will read the redirect
even from from the action.

And so here, like we get user errors, and we need to dispatch
another another type. Actually, we were not handling these types, yet, you will see in
a moment what these types do. So here we need to dispatch another type. Another action with
the type, clear error, clear errors, just in case there is any errors in our form. And
then we actually redirect. And if there is any problem, we need to not set date, we need
to dispatch an action with the type set errors. And with a payload of error, dot response
dot data very similar to what we have inside the component. But this will actually do this
to the global state. Now let's let's go to the reducers and handle these types. So let's
go to the the user reducer. So here, we're going to need the actions, I mean, the types
that we have as well. So let's do a springing set, we can actually just copy not from login
from the actions, we can just copy these types from that we've run, Oh, actually, I forgot
something, we need to bring in axios, because we're using it inside the actions.

So from
axios. And here, we copy this, we go to use the reducer we paste them. And here is where
we need to give an initial state an initial state to our This is not the global state.
But this is remember this is what's stored inside of this user. So this real reuse the
reducer is actually this state, of course, it's going to change it's not going to stay
the initial state. So we're going to have a an authenticated Boolean, which is going
to be false by default, we're going to have credentials. If you remember, if you've seen
our API, you know what these are, we're gonna have a likes array. And we're gonna have a
notifications array. And initially, everything will be empty. And here we will export default
function, and this function will take a state. And here we give initial state as the initial
like the default value of the state.

And the second parameter is going to be the action
that we receive. So here, we're going to have a switch. So depending on the action, we're
gonna do something actually not depending on the action type, we're gonna do something.
So here, this is where we catch all types. So cat case, first one will be set authenticated.
And here, we do remember this word switch. So we do have a colon here, and we we here,
if we get the type set authenticated, this is a simple type that I'm going to actually
call from the app dot j s, this just returns the state. And each time we return the state,
we actually spread the state that we already have, and then we change a couple of things
in it. Here, what we changed is the authenticated, we make it true. And let's handle the set
unauthenticated state. We're not using actually these two types in this video, but we will
set them for future use.

And here, we just, if we set on authenticated, this is going
to be used when we try to log when we log out. So here we just actually returned the
initial state which has authenticated a false on a no data. Now here we can handle the set
user type, which we just dispatched from the user actions. And here we simply return authenticated, we set it to true because we
got the user data. And we need to spread action dot payload. Because remember from our API,
when we send our token to slash users, and we get the data, we actually get something
like this with credentials and lights and notifications.

So if we just spread it like
this, it's gonna bind the credentials to credentials, likes the likes and notifications to notifications.
And of course, this is a switch. So we need the default case. So default, we just return
return to state that we have right now, which is this. Alright, so let's save this. And
let's go to our login. And here in the login, now we need to connect to this component to
to the Upstate. So here we bring in two things, let's say here, Redux, Redux stuff. And here
we bring in something called Connect, which does that. And this is from react Redux. And
we need to bring in the action, the login user action. So here we do import login user from. So we go back actually one level to Redux
slash actions slash user actions. So here, instead of doing what we did earlier, we actually
just do this. Actually, we need to bind it first. But let's just type this, this dot
props, oops, this dot props dot login user. And remember, we pass it the user data, which
is user data right here.

And we pass it this dot, props dot history. so that it can use
it to redirect us on success. And here are the bottom, we need to actually use Connect,
which is another higher order. component. Let's cut this and let's do connect. And let's
leave this empty for now. And the second one will be our width style styles login. And
here it it takes. It takes three things, but we have those three things we need to one
is called map state to props.

We'll create these in a second. And one is called map actions,
to props. And the map state to props whose will be const. Map state to props, it's going
to be a function that takes our global state, and returns. So now it takes global state
and then from the global state, we take what we need, basically. So right now what we have
is we have user data and UI. And for the login component, we don't need data because we don't
need to show any screens in the login thing. So it makes sense that we only get the user
and the UI. So let's actually do that. So let's get user. And we'll be State DOT user.
And UI will be state.ui.

Alright, UI like this. And here, we need to say as well const,
map actions, to props. And this will, we're telling which actions we're actually going
to use. And in this case, we just need logged in user. So we passed them here. And actually,
this will be props. All of these will be props. So let's add them to our prop types.

So here
we say, login user is a prop types. It's actually a function. So prop types.func.is, required.
And we have user which is an object, I'm just going to copy this. And then we have UI, which
is one object, and I'm going to paste this. So yeah. Alright, so now the user and the
UI are actually brought in from the global state and mapped into our component props.
So these will be in our props right now. And so is going to be the login user. This is
why we can actually here do this dot props dot login user. And here, what we need to
do is the loading now we no longer have it in our local state. We have it in the props,
so we can get it from the props. But of course, we can't just get it like that. It's inside
the UI.

So we do UI and then colon, and we get it from inside the UI. And I think this
is it for here. One thing we're not doing is we're not actually here when we get the
errors, we're not handling that. So user actions. Here. When we do set errors, we need to handle
that from the UI reducer. So in UI reducer, we need to Bring in set arrows and clear errors
and loading UI actually as well. Loading underscore UI from go back one level and then types.
And here we need as well as an initial state for this. And our UI reducer will hold the
loading, which is initially false, and an errors object, which is not initially. And
here we do the same thing, export default function, which will take a state, the initial
state, and we'll take an action as well. And here we do a switch. And here depends on action
type, types type.

Here, we have a list of default list or default, which is returned
state. And here we can do case, what's the first ones that errors? So if we get any errors, we actually, we just
spread, so we just like spread the state. And which, what do we do actually? Actually,
yeah, we said the loading to false because we finished loading, we actually got some
errors, and we set errors to our action dot payload. And if we get the clear errors, case,
we do return state. And we said the loading false, and we set errors back to No. We have
loading you actually as well. So let's do case. Loading. UI. Oops. Here, we just return Oh my god. Return state. And we
just set the loading to true. Alright, is that everything, get set errors? Clear errors,
loading UI. Okay, this look looks good for now.

I think this is everything. Let's check
if we have any errors. We don't actually stop this and run it again. Hmm, no errors. That's strange. Okay, so let's
open up the console. I mean, put them side by side. Do we have a token? No, we don't.
Okay. All right. Oops. All right. That's what our first error login user is not a function. Is it not? Because I didn't save this file.
Okay. Okay, let's try to login. So user at email, com 123456. Login. Oh, actually login successfully.
And we got the token in the storage. Let me delete the token. Actually, let's look at
the Redux state.

So state. All right, cool. We got our, like user details mapped into
our into our user object and the state. Oops, let's go back to row Yeah. All right. So we
got our user we got authenticated equals true. Let me actually reload to see the initial
state. The initial state is what we had it and authenticate to this false. And if let
me actually try wrong credentials are interesting. We get an error here, but
we don't get it here. Hmm, I get errors here. But what they don't show up. Okay, okay. It's because these props don't
come straight away. Actually, we need to do component component will receive props and
this takes Next props. And here what we need to do simply is this dot set state. Yeah,
we need to get the errors and then set them to our local errors. So set state and we do
errors equal next props.ui that errors. All right, actually, we need, we need to actually
put a check, because we will always be receiving props.

And this will be inefficient, we need
to do if next props.ui got errors. So if we get this, then we actually set the errors
to the errors object. This should fix it. Alright, let's look at our state, we have
no errors and, and there we go, we got our errors. And they're shown on our login form.
And if I fix just this, say, user email.com, or hit send, I need the password. If I have
a wrong password, code, get the general one. And then if I have the right password, we
get redirected. Sweet. Let's go to the signup component. Where is right here. Okay, we need
to actually first let's create the action. So let's go to user actions. And here let's
create an action that's like login user, but it's the sign up, it's actually going to be
very similar. So we can just copy this, and then paste it here. Instead of login user,
this will be sign up user, it's going to take the same stuff here, let's call this new,
or this way, let's Ctrl D, and then call this new user data.

Just for readability. With
dispatch, login, loading user loading UI, that's fine. We'll change this to slash signup,
we send the request to slash signup. And the same thing happens here we said the token
will get the user data and we clear the errors, we push the home page. And we set the errors
if any cool. But one thing though this code is repeating itself. So let's let's make it
into a helper function. So let's cut this. Let's make a function here. Let's call it
set authorization header. It will take the token. And here we will have that same code.
But instead of restaurant data token, it will be just token which is this function argument.
So we can just actually call it from here.

So here as well. So here we just do SATA theorisation
header when we pass it res dot data dot token. And let's copy this and instead of all this
in the login, we paste it. So set authorization header, read set token, header, data dot token.
Cool. Let's create actually another action for for logging out. So const, export const
log out user. And this won't take anything and think you won't even take this bachelor
will think that Well, alright. Yeah, well. Alright, so here, what we need to do is we
just need to remove the token from the storage. So we do local storage, the rim remove item,
and we just pass it the name of the item which is as a string, of course, FB ID token.

And,
and here what we need to do, we need to remove the header, the authorization header from
the defaults of axios. So we can actually just delete the entry by doing delete like
this axios dot headers, not actually dot default, defaults, dot headers, common and the header
is authorization. And here we need to dispatch a type an action
rather and of type set on authenticated our product, we brought the end and we have it
in types. So this will clear out our user state if you remember, if we go to use a reducer
it will set unauthenticated will return the initial state and it will it will set us back
to being not authenticated and having no credentials and nothing.

Let's remove these unused imports
right now so I can get rid of the warning. Let's save this. And this is well let's go
to sign up and actually Start using that. So here we're gonna bring in. So we're gonna
bring in oops import, connect, let's say Redux here Redux Redux stuff. And here is to connect
from not equal from react Redux. And we need to bring in the sign the sign up user from
Redux, go back one level, go to Redux slash actions slash user actions. Alright, right.
And let's go to the bottom and actually connect the components. So here we do export default
Connect. And we pass a map state, to props. And a map state. Now, map actions, to props.
Close this, and then we open another parenthesis, and we close another set of parentheses. And
here, let's say const. Map state, to props. equals equals, it takes the state and it returns.
So we need the user. So user equals or colon State DOT user. And we need the UI. So state
state.ui.

Okay, so yeah, we need the map. Actually, we, we can just pass it like this,
because we only have one action. So it's still clean to type something like this. So log
out user, without actually putting it into a variable and putting it there. Let's add
them to the prop types. So we have user is a prop type stock, almost typed user object
that is required. And we have UI, shares, prop types, the object that is required. And
what else we have the function log out user is a prop types.funk.is required. All right,
and we brought the function. So we need to use it here when we submit. So we can cut
all of this. Actually, we already have it in the other code. So we can just here we
just say this dot props. Remember, it's in the props already logged out user and we pass
the new user data or just call it user data here, let's change this to a new user.

They
that doesn't make that big of a difference, but it's more readable. So this dot props
dot history, we pass it so that we can redirect. And yeah, I think actually, now we need to
set the errors. Let's just copy this from login component will receive props. But here,
and let's remove the loading from the state, we keep the errors because we can set them
from here. And here we from the props we get from the props from the UI, we get loading,
removed the loading from the state, and this should be fine. Let's save. Let's see if we
get any errors. We do. logout user is not defined in signup.

Oh, not log out, sign up.
Why did I put log on? So actually sign up. Okay. And here's what sign up. Not sign up
this dot props dot sign up. Alright, so that should be fine. Forgot to sign up. Actually,
we're logged in. So let's go to application. Let's remove the token. Let's go to sign up.
Actually, we need to fix this because it needs to know. Okay, we got to sign up. We'll fix
the author out in a bit. Right. If we send a call, we get the errors. And let's try to sign up a new account new
six@gmail.com 123456123456 handle the new six cent sign up. Cool. We got redirected.
We got our token. Everything works. All right. What else? Let's go to the app. So here the
way I want to check is that I want check if the token is in the storage, but this authenticated.
Obviously it's really bad practice to have global variables like this.

So we need to
call the action from, from, from our user actions and set ourselves to to be authenticated
and then edit the state accordingly. So here at the top, here under Redux we're gonna bring
in, we're gonna bring in two types, because we can actually call them from here as well.
So we're going to bring in set authenticated, we're going to bring in set errors, or do
we I don't think we need to actually know. So just set authenticated from go back one
that actually we don't get on the same level Redux slash types. And we bring in the logout
user, because in case the token is expired, we just log out from here logout user and
get user data, how we created get user data we have yeah.

Oh, yeah, of course, we have
from Redux slash actions slash user actions. And here when we compare the token. So if
it's expired, we just do, we can actually do store dispatch. And here what we need to
dispatch, we need to dispatch the action log out user. And that will delete the token and
log us out. Let's get rid of this authenticated variable. And we are as well like set the
href to slash login, so we get redirected. And let's remove this authenticated equals
true. But instead, let's do store dot dispatch. And here, we dispatch an action with a type
set authenticated, which just sets authenticated to true. And then when we go to the homepage,
we actually get the data or when we call get user data, we get the data.

So let's do store
dot dispatch. So after we dispatch that we are authenticated with dispatch, get user
data. And actually, actually for this to work, because when we set axios default headers,
when we actually refresh the page, those headers, like those defaults are gone, and axios is
re initiated again, we need to again do axios dot default, or we need to bring in axios.
And VS code did me the courtesy of doing it itself, but it did this capital thing.

Axios,
the default dot headers, dot common. And here we say authorization. And it's equal to the
token that we have up here. Not rochen token. All right, and then we get the user data,
this should work. But because we got rid of the authenticated thing, we can't use it here.
So let's delete that. And but I think our throat will complain because we're let's fix
authorizers Well, we might as well, since we're here. So let's bring in Connect, we
need to connect to this component as well to our, to our state. So it's bringing connect
from react Redux. And now actually, that's just connect. And let's explore the fault
Connect. Map state, to props. And we don't need any actions. So we can admit that the
argument and here we do const map state to props equals, it takes in the state. And here
Oh, actually, this function returns an object. and here we can actually even get a certain
key within an object. So we can say authenticated, and then do State DOT user dot authenticated.
And you will get just that one key.

One property. And here, it's it's going to be in the props.
So nothing changes here. So we get authenticated from the props. And then we get here, and
we redirect if needed. Let's do actually prop types as well, because, you know, you never
know what's going to happen, because they're prop types. And it's always good to practice
these, these best practices so that you get used to them. Alright, so prop types. And
here we say, what is the author route of Route dot prop types, equals, and what do we have?
We have just user so prop types dot object Thought is required. Actually, this is a capital
P. and everything should be fine. Let's save all files. Sign up. axios is defined Oh, actually,
we don't need axios anymore here. Because we're doing that from the user actions. We
have axios in the login as well, let's get rid of that. All right, we will use these.
So let's just ignore that warning for now. Let's go here. Let's see we have a token.
And if we click here, it redirects us.

And if we delete the token, now click here. Hmm.
Somehow that arthralgias, not working. we deleted the token. But we're still we're still
logged in. Oh, because we need to actually, oh, this executes once the app is submitted,
actually, it's behaving as behaving Normally, I don't know what I was thinking. Because
that would be triggered. Actually, because a login would not be triggered by someone
deleting the token, it will be triggered by us deleting the token from the app, there
will be a login button and that login button, when you click it, it doesn't just delete
the token, it actually sets the state to unauthenticated. So yeah, no one will actually go and delete
the token like this. If they do, they will actually break our app, and we have no way
of fixing that. Alright, so this is our application right now. And right now we don't have a profile.
So let's actually create that let's create a section where we show the profile because
we if we go to dev tools to Redux, we actually are fetching the profile, we have all these
details, we just need to show them on the interface.

Alright, so let's go to the homepage
is the homepage here. So here we have this text profile, and it's actually put a component
profile, which we haven't created yet. Let's import it. Import something that hasn't been
created yet. Because why not? Alright, let's go to components. Let's create a profile dot
j. s. And here it is. Do RC top whoops. Again, it didn't work. Come on. Yes, Third time's
the charm, I guess. All right, so let's remove the export. And here we're gonna need a couple
of things. Of course, we're gonna have prop types. So prop types. What is that prop types
from prop types. We're gonna need with styles. For material you wore slash core slash style slash,
with styles. We're gonna need some movie stuff. So we're gonna need the button. From material
UI slash core slash button.

When I know we're going to need some icons actually need to
install the package for icons. So let's open up a new window and do an NPM, install dash
dash save to material, UI slash, slash icons. let's actually look at the documentation.
So basically, these are all the so we go to styles, icons, these are all the material,
Google Material Design icons, there are SVG icons. And the way you use them is just like
you import the icon with the name of it. So let's say delete. So import, add material,
UI slash icon, slash delete, and you use it as a react component. And if you would go
here to see the full list of the of the Google Material Design icons, you know, I said the
whole thing again, you can see all the icons and if you want to use one, basically, you
just camel case the name so for example, Play for Work will be not camel case basketball
case. So it would be like Play for Work, and you will get that icon.

Alright, so let's
head back to our application. We're not going to use any icons right now. But here at the
start, actually, we need to first let's say with styles, styles, unwrapped the profile
as well. And then let's wrap the entire thing. And here that's connected, connect, which
we haven't brought in yet and brings the connect from HTTP to okay VS code. Perhaps the To
props. I don't think we need any actions for now. So here let's do, we bring Connect, not
actually from react Redux.

And we need to create the map state the props. Takes the
state the usual, and it returns an object. And we only need to access the user so users
data user. And all we need to do the prop types. So let's do what is this profile. So
profile, prop type types. We have user some object, it's required. And we have classes
from a spouse. Almost typed classes. And this is a required call. Okay, so here at the start
of the render, let's get get classes.

And let's get some details from our user. So from
user let's as well destructor, from this, actually, inside of us that we have credentials. And from that, we're going to need some stuff. This is some
nested destructuring. So we're going to need handle, we're going to need to create the
art image URL. What else? Oh, yeah, we need the details. So bio, and website and location.
Alright. So this is what this is after credentials. I confused myself a bit. Yeah, that's it,
we need the credentials. And we need the Well actually, actually, we need to create another
property I forgot about. So inside the user we're going to have. So here we put a comma,
we do loading, we're gonna have a loading for the user. Let's not forget to say this
equals this dot props and save. So formats, we're going to have actually a loading property.
So when the profile is loading, we can see a loading skeleton.

So which is different
to the UI loading. So let's go to our user reducer. And here we need to bring from types
loading user. And here we need to initialize a property loading with false. And here, let's
add a case for that case, loading user. And all it does here, we just return the state.
And we do loading equals true. And here, when we set the profile, we actually stop the loading.
So we do loading equals false. In case it was true.

So let's save this and let's go
to use the actions. Let's bring it in as well here. So from types loading user, oh, it's
already created, actually, it's already in the types. Okay, so loading user. And here,
when we try to get the data, that's before we try to get the data, we dispatch an action
with the type loading user. I think we're done with this part. Yeah, we're done with
this part. So let's go back to our save the home, let's close this. Let's close this,
let's not worry about this. Let's create concepts styles equals empty object for now.

I noticed
I'm spending too much time writing CSS rules, which is not the main focus of this course,
on the series. So what I'm going to do for now, I'm just going to paste in like stars
for this profile, because there's quite a bunch of them, I don't want to I don't want
to waste time doing that. I'm gonna Of course, post the link to this, this object style subject.
And so you can copy it and paste it right now as we're doing this video.

And then you
have everything styled. And you can go Of course through it and and you know, and understand
what's happening the way I wrote what I did. Okay, so here, we're going to actually create
one object and then return it. And then we're going to call it profile markup, because this
markup is going to be completely different depending on whether we're loading or whether
we're syndicated.

So here we have, let's do let profile mark up. Now we're going to have
this is going to be a bit confusing. We're gonna have two ternary operators. So the first
one, let's say, if not loading. So let's do question mark, parentheses colon parenthesis.
So if we're not loading, show this for loading show this. So for loading let's For now, let's
Just show a paragraph say loading dot dot dot. And if we're not loading, don't worry
about this, it's going to be fixed once I write anything here. So if we're not loading,
which check if we're authenticated. So if we're authenticated, show this, else show
this. So if we're not loading, if we're loading, show loading, if we're not loading check for
authenticated, if we are authenticated, show the profile of authenticated. If not, we're
going to show you know a section that says there's no profile data, please log in or
sign up. And we will show two buttons for users to do exactly that.

So here I'm going
to use something called paper from material UI is basically just like, Where is it? So
component demos paper. So yeah, this just this kind of surrounding frame, thing that
stands out from the background, it looks like a card because basically a card is built on
top of a paper. So here with the paper, I'm going to give it a class name of classes,
paper. So we already have the style. So this styles will apply and it will look cool off the go. So here, I'm going to do
a oops. So this time here, let's do a div with a class name of and then this profile.
And here, I'm going to have a wrapper for the profile image. And actually, we could
still use traditional class name, you know, strings, we can, if you go here, and you see,
we can still use stuff like this. So inside of profile, we can say and space, and then
we give the class and it will still work like traditional SAS.

And yeah, so we can do that. So this is profile image,
actually not image profile. So profile. Or is it a profile dash image. So here inside
of this div, we're gonna have the, the image, Sony image, or just image tab, and the source
is going to be image URL, we already disrupted that, and the alternative will be just profile.
And it's gonna be okay, I'm just going to leave it like that.

For now, here, we're going
to do a horizontal ruler, which I've already styled to not have any border, so it will
be invisible, just create some space between them. And here, here, actually, I'm going
to put a link, but this is not going to be like the normal react link. Actually, it is
but indirectly. But here, let's first bird div with the class profile details. And I'm
going to bring in something from material UI.

So this is not more stuff. This is Redux stuff,
Redux. And hear from Mui. I'm gonna bring in what is it from material? Why is it not
until the sensing material dash UI slash core slash link. And I can name it anything,
because the default is the default. Export, I don't want to confuse it with the React
router Dom link, which we need to bring in as well. So import link from react router
DOM. And here, where are we? So we're here, here, I'm going to say, movie link. And I'm
going to give it the component of link. And here, it's gonna have the two, actually, it's
going to be like this template string, it's going to be two users slash, put a variable
there.

And it's going to be the handle of this user. So this is going to be like a title
that says the name of the user, and it's going to be a link as well to that to the page of
the user, and the color will be primary. And since this is built on top of typography,
we can give a variant to change the size. And I'm going to give the vine variant of
H five, header five, and this will say at handle, just like in Twitter, and here, we
will do an HR.

And here I want to show an always show the details of the profile. So
first, first will be the bio. So and these, we don't have to have them because a user
can have no bio, so it's going to be no. So what we need to do, we need to first check
if they have a bio. Then we show the bio. So here what we're going to use, we're going
to use typography, typography.

And is it important from the right place? Or not like this, I
need to shake this. So typography need to put up with movie stuff. Okay. So here, this
is going to be typography of variant. What variant do I give this body to, I guess, think
its body to pretty sure its body to so here bio, biome bio. And after this, I'm going
to put another HR to make some more space. And here, I'm going to check if a user has
the location.

And here I'm going to do parentheses because there's going to be multiple things
I want to use like an icon on the left, that shows a look location icon. And this is called
location on me bring it in from icons. So this will be here. Import location on from
material UI should not slash core slash icons slash location on I'm going to need two more
icons, so might as much excuse me bring them now. I'm going to need the link icon. I'm
going to call it link icon.

I own icon. And it's gonna be from icon slash link. Shoot
me check. I don't remember what the other icon was that I need to bring. styles. icons.
calendar, but calendar Yeah, calendar today. Okay. All right. So it's gonna be let me select
this control the calendar today. Alright, so here. Where are we? So location on? Color
primary? Yeah, that's it. And here next to it. I'm going to do space, actually without
which is do spawn location inside like this. And I'm going to put an HR but it has to go
inside of here. Because if there is no, if there's no location, I don't want to put two
hrs on top of each other. Or this has given me a must have one parent element. Oh, yeah.
Okay, let's wrap this in a fragment, which if you don't know what it is, it's a react
component that actually doesn't render anything, but just wraps things so that they will be
in one element.

So let's actually bring that in. fragment. And here we need to show the
other way. Yeah, the website website. And, and, and two parentheses expression. So another
fragment as well. And here lets us use the link icon, so link icon with a color of primary.
And, under the link, I'm going to actually have a normal anchor tag anchor tag with an H ref to the website, I'm going to
give it a target on the scope blank so that it doesn't open in this window opens in a
different window.

And this is a react thing you have to give this REL equals no opener.
No referrer otherwise, React will complain. So we close this on inside of her. I do like
oops. Because this icon is kind of thin on a give like some it's kind of white, I'm gonna
give some space and then put the website like this and put in like a horizontal ruler, HR.
And here under the website, I'm going to put the the joint since date thing so I'll put
the calendar to the icon with a color of primary again. And after I'm going to put some space
like this, and I'm gonna put a span and so joint and here actually we need to format
this so we need to bring in DJ s so let's say important they j s from DJ s.

And where
are we we're here. Wait here. So here I need to say de JS past this the created art And
here I want to format and pass a string, say M, which is going to say like the month but
in three digits, line three letters, and quadruple why to just show like the the year in a normal
format. Alright, so this is for the profile. But here I want to show as well if we're not
authenticated. So here let's do paper, again with a class name. Oops, class name of classes,
dot paper. And close this.

And then inside of here, we're gonna have some texts type
Pog Rafi with a no color variant of body two. And I'm going to give this a line takes a
property align, and say center. So the text is actually aligned in the center. And let's
say no profile found, please login again. Here, I'm going to put a div div, and this
is going to have a class name of classes dot buttons. button, what buttons? buttons, yeah,
buttons. Alright, so buttons. And here, I'm going to put a button. Did we bring in button?
We did okay, I am going to put what is this first button. And this will have a variant
of contained, contained like this with a color primary color primary with a component of
link so that we can actually go somewhere within our application with a tooth to slash
login.

And this button will say login. And we can actually just copy this. Copy this
button. Right here. We'll have the color of secondary and it will go to sign up. And he
will say sign up I think this is it for our profile markup. Yes. So yeah, for logged in,
we will show this for not where shoulders for loading will show this. Okay, let's save.
Our paper is not defined how we need to bring in paper. So let's copy this. Select this
Ctrl D save paper. What else? authenticated is not defined? How come? Oh, we need to take
authenticated as well from user so authenticated. So theme is not defined. Oh, we need theme
we need to spread theme here. Actually, we need to take theme. So do like this theme.
And then wrap this in parentheses so that it's returned from the function. Let's save
and it should fix everything and it does. Cool. Oh, okay. So our image is massive. But
the rest is cool. Because this image needs the class what is
the class actually profile image this so what is the image? Class Name? Equals that at save
Oh, that's a line to the left for some reason.

That's what from actually Oh, actually the
div that contains his his image dropper and not not not profile image. So delete this
and then so rapper. Alright, cool. So our profile is like this, we show the website
person has Twitter as their website joined in March to 2019. And if you would like logout,
of course now manually will implement a logout button in the next episode. When we finish
up the profile call, we get the buttons and click on login, it goes to login and click
on Sign up it goes there. If I would sign up as let's say john, who doesn't have any
bio or anything. Go ahead and turn. There we go. We don't get the details that this
user doesn't have and the image is running quite nicely.

Let's start implementing some
action buttons where we can add details for our user. Alright, first thing I want to work
on is the image upload function. Want to add a button when we click it, we can select an
image and upload it to our server. So let's go to profile Jess. And here right under the
profile image, we're going to add an input input of type file. And it's gonna have an
ID of image, or let's call this profile image or image upload or image file. image or image
input, I don't know, I didn't feel creative in that moment. So onchange, eight equals.
So this input itself is going to trigger the, the handler function.

So let's call this handle
image change. And this the way a file input file input works is that the on change is
triggered each time you select a file. So if you click and you select the file, the
on change is triggered. And the way I want to set this up, I don't want to set up two
buttons where you select one image, and then you click Upload. Because that's a bit too
much for our profile, what I want to do is that once a user selects an image and clicks,
select, it automatically uploads to our server. So let's go here and create this handler method.
Let's call this handle image change, it's going to take an event because it's an input,
after all. And here, what we want to do is we want to get the file. So how we get it
is let's do const image equals, because this is a file input event target, it's going to
have a property files. And because we said file, we can only select one, but it will
still have them in an array.

So let's select the first one. so files zero. And here, we
can open like do a comment here, like send the server, I just want to look at it right
now and see if it's working. Okay, so we can actually spend some time and style this and
change these, these things that come to choose File message and remove this message. But
what we can do, which is more easy and convenient is that we can just hide this and put a button
here, and that button will trigger the input.

So what I want to do is I want to add this
a property hidden with value hidden, so we don't see this. But what we do is that we
add a button next to it, that when clicked it triggers this input. So it's the icon,
icon button I'm going to use which is a it's built on top of button is just an icon that
triggers an event and then you put a button inside of it so that it looks like well it
has a button. So on click equals. And let's call this handler, handle, edit, picture.
And let's give it a class name of button.

Remember, we've already written those CSS
rules. So here I'm gonna put a an edit icon, which if you go to material UI icons or Material
Design icons, you'll see it's just a pen. And I'm gonna give it the color primary. So
let's bring these two things in. So here, under Mui stuff, I'm gonna do import icon.
button from material UI slash core slash icon button.
And the edit icon, import, edit icon from material UI, slash icons slash edit like this.
Alright, so let's create this handle edit picture function. Go here and say, handle
a picture equals takes no arguments. And what it does is that it needs to find this input
and just click it basically. So what we need to do is const file input.

And we can get
it since it has an ID. So let's do document dot get element. I don't know why I'm not
getting IntelliSense here, slow, okay, so get element by ID, and the ID will be OCR
the image input. Now that we have it, we could just say file input dot click, simply and
it will actually click it which will open the selection file selection window. And then
when we select an image, it will trigger this. So let's save. And there we go. We got our
button and the other input actual input is hidden, and the button is already placed in
its perfect spot because of the CSS rules that we pasted in the last video.

So if I
click it, it will actually trigger the input. And I can select a file, and I don't see the
name of the file selected or anything, it's just done behind the scenes. Alright, but
what I want to do actually, this button, and maybe it's not that descriptive, so I want
to use something called a tooltip. Which if you go to material UI on component demos,
right here, tooltips is basically when you hover over something, and you see this message
that kind of helps you tells you what this does. And you can place it on any side, I
prefer the top.

So the way you do this, you just bring in this tooltip from material UI,
core tooltip. Let's copy that. Let's go here under Mui stuff. let's paste that. And the
way it works is that you surround your element with a tooltip, like this. So if you want
this button to have a tooltip, you just surround it and you put a title and a placement. So
here, our icon button here, let's cut this, and let's do two tip, it has a title on here,
the title, I wanted to say, edit profile picture.

And the placement is dope. I think the default
placement is bottom. So okay, let's paste that. If you want it on the bottom, you can,
you can do that. But I just prefer the top. So let's save. And let's see what it looks
like. Alright, cool. So we get our message when we hover over, which is very helpful.
So it's good UX acts, practice. Alright, so let's actually send our file to the server.
So not here, here, what we need to do, we need to send a request of top with with form
data.

So let's create that. So let's do const const form data equals new form data. Pascal
case, because this is a class. So let's do form data dot append. So we're going to append
a value like an input to the to the form data. And this takes three things, a name, which
is going to be a string, and let's just say image. This doesn't matter because we know
what our server code looks like. But let's call it image, or value, which will be image,
which is this file, and a blob, which is going to be image dot name. And here, we can actually
send an axios request from here. But of course, since we have Redux, let's centralize everything
in the user actions. Plus, we need to trigger the user loading action. So let's do this
dot props, as call an action that we haven't created yet.

It's upload image. And let's
pass it this form data. Simple as that. And let's go and create this action actually.
So let's go to actions, user actions. Here at the bottom, I'm going to do export const, upload image, it's going to take form data,
and then do the following. So let's do axios dot post. But actually, before that, let's
call the, the user loading action. So let's do let's dispatch an action with type, not
user loading loading user. And actually, I forgot to include the dispatch. So here, we
need dispatch. So let's add it here. So dispatch. So after we dispatch the action, we can send
our request. So post, if you remember, this is to slash users slash image. And the data
will be that form, not don't form data. And here, then we get a response.

What we need
to do here, we just dispatch the get user details, get all get user data, and then get
like basically get our user. So then here, let's do catch error, which is console log
error. And here, we don't need this result. So we can just have an empty function arguments
there. Yeah, I think this is for the upload image. That's actually important in the profile.
Here, import. Let's import the logout function as well because we're gonna, we're gonna use
the logger actions Oh, we're gonna use it later. So log out user. And upload image from
go back one level Redux slash actions slash user actions.

Alright, let's go to the bottom
and a create a map actions to props. So here's the const. Map actions, to props equals an
object which has logged out user, an upload image Unless passed, that is the second argument
to our Connect. So map actions to props. And let's add them to the prop types. So here,
let's say logout. user is a prop types.func.is. required. We need to upload image, oops, upload
image, prop types.funk.is required. Alright, let's save all files, and the dev server is
still running for me. Let's go to the application. Let's click on the on the button, let's select
this guy's image, and it loads and there we go, we got our image, and even uploads on
the spot right there, because we dispatched the get user data action. And if we do it
again, we put this monkey image. And there we go, we get the image uploaded again, so
cool, it's working. And if we go to our data or storage bucket, we see that, of course,
the images here.

So the latest one is this. Actually, we might later add a DB trigger
that deletes the user's old image and then uploads the new one as well. So in this video,
we're going to create two buttons in the profile section, a logout button and the Edit Details
button. So let's do that. Alright, let's go to our text editor. And let's go to profile
images. And here where we are not loading and authenticated
at the bottom here after this div, let's add.

So first, let's add the logout button, which
is we've already we've already imported the logout user function, or action. So let's
do that. So let's use it. So here, let's say, I'm going to surround this with a tooltip
as well. And the title of the tooltip will be logged out. And the placement will be at
the top. And here we're going to have our icon button. And the onClick for this on click
is as cold as this thought. We call it handle logout. And let's close it. And inside of
here, the icon that I'm going to use is called keyboard, keyboard return. And it's going
to have a color of primary. Let's close the tag unless there's an error her nights Fine.
Let's bring in the icon.

So here on the icons as to import keyboard, return, oops, import
keyboard return from material UI slash icon slash keyboard return. All right, and this
handle logout let's create that so handle log out. It's actually just gonna call this
this dot props dot log out. user. All right, did we actually add that to our? Yeah, we
have that we have that here. We've imported it. And it should work fine. Let's save. Let's
look at our app. Did we get an error? Now cool. So we get this error back and click
it we actually get logged out. Let's look log back in. So the user at email, comm 123
through six. All right, we're back in. Now let's create a button for editing these details.
And for this, I'm going to use the the dialog for go to component demos dialogue.

Let's
try this one. Not this one. The one with a form. Yeah, this one. So we're going to have
something like this A dialog that has three fields, one for the buyer, one for the location
and one for the website. And if we do like it's going to be saved instead of subscribe,
and that will send a request to our server. And the way dialogues work is that you're
going to have a button or a button at the top. It's this one that triggers the dialogue
to open and then you're going to have the content of the dialogue. But since this will
have a lot of code, let's actually put it in its own component. So here under the logout
button, let's say let's add this component called edit details, which we haven't created
yet.

Let's go up here and it's important To end, so added details from we go back one
level, we go to components, slash edit details. Alright, let's go to components. Actually,
it's in the same directory same is on the same level. So just do like this. So here,
let's create a new file called edit details, dot j s basketcase, of course. And here, let's
do RC tab. Again, come on, there we go. Let's remove this export. Let's take these three
imports, because we need them. So we're going to need fragment as well, any prop types.
Let's, let's do a styles here. const styles is we're going to need the global theme. So
stick the global theme and return. Let's just spread the theme for now. We need to add anything
we're going to add it later. And we're going to need Of course, Redux to get our details
from the server and actually show the values on that form. So let's say import connect from react, Redux. And we're also going to need
an action that we haven't created yet, let's actually create the action first, not data
actions in user actions.

Let's go to the bottom here, as to export const. And this is going
to be the function that sends a request to edit our details. Let's call it edit user
details. And you will take user details. I knew it needs dispatch. So let's take this
patch as well. And here we start by dispatching an action with the type loading user, is it
Yeah, it's loading user. And here we send our request. So axios dot post, and it's going
to be to slash user is going to take the user details, object, not post them. Here, when
we get our response. Actually, we don't need the response, because we're just going to
call get user data from here. So with dispatch, get user data. And here's the catch if we
have any error, let's console log it.

Alright, this is done. Let's save this. And here, let's
bring it in. So import the user details from the go back one level Redux slash user actions,
slash, not just user actions, actually slash actions, slash actions, slash user actions.
Alright, let's connect our component. Let's cut to this edit, edit details. And I'd say
export default Connect.

And we're gonna have map state, to props to props. And here, we're
just gonna have one action. So let's do an object like this with the action edit user
details. And here let's do with styles. We pass in styles. And then for the second one,
we pass in our edit details component. Alright, let's create our prop types as well. So let's
do edit. Details. Prop types, equals, the first is the function so edit user details
is a prop types dot func that is required. We're gonna, we're gonna need classes as well.
Prop types.object.is required. And I think this is it. Yeah. Okay.

So, here, we're gonna
need to initialize the state. And in our state, we're going to have three fields bio, which
is going to be initially an empty string, website, an empty string and location, an
empty string, we need a Boolean for open, which is going to be initially false, because
by default, it's it's closed the dialog. And here what we need to do is that we need to
once this component is rendered, once it mounts we need to get the details from that we have
of this user and put them as the values of our input. So let's say if our location says
Los Angeles, California, we want to when we open the dialog in location, it will be already
written there so that the user can edit or change And if we don't have anything, of course,
it's going to be empty. So here in component did mount. Actually, we need to create our
map state the props, const map state to props, it's gonna, it's gonna be a function that
takes the state and returns the following, I can actually get credential just credentials
we need.

So we do create done shows, it's going to be from State DOT user dot credentials.
Alright, so here, in component did mount, we need to do this dot set state, we need
to set the bio. And we could actually in our credentials not have a bio, so we need to
check for it. Otherwise, we're going to set it to undefined. So what we need to do is
we need to do this dot props, actually lets the structure the credentials, const creed
done shows equals this dot props. And here, what we need to do is that we need to say
credentials dot bio.

So if we have, so a ternary operator like this, if we have done, we have
a bio, let's say. So we just say that again. So the value would be this, else, it's going
to stay empty. So let's copy this other comma, space that paste it twice. So let's replace
here Ctrl, D, and say website and control D and say location. All right, so when the
component is loaded and mounted, it's going to set these values. So let's create our,
our dialog. So here, instead of this div, I'm going to use fragment. Oops, it didn't
close. Did we not bring it in? We did that Oh, why didn't close to. So fragment. Alright,
so inside the fragment, so first thing is going to be our button, which is going to
be inside a tooltip.

And the title of the tooltip is going to be edit details. Placement
as usual, on the top, I don't know why these tags are not being closed, is it because I
didn't import them? I think because I didn't import these things. Let me import stuff that
we're going to use. So import tool, from material UI slash core slash tooltip. Let's copy this,
we need icon button. Actually, we can just bring in some stuff from here. So let's just
bring in all this stuff until here. I spaced that before. So we're gonna need this icon
button. And we're gonna need the edit icon. So say import edit icon from material UI slash
icon slash edit.

I'm here I'm just gonna say icons. Here. I'm gonna do Redux, oops. Redux
stuff. And here, say movie stuff. Alright. So now, if I do this, yeah, closes the tooltip.
And here we have our icon button. icon, button. The on click. Let's call it handle open. And
let's give it a class. So I know we're gonna need to style it later. of class classes dot
button classes. Actually, let's destructor classes as well. So let's do const classes,
equals this dot props. Let's close this. And inside of here, we're going to have our icon
which is the edit icon with a color of primary. Let's close it. Actually, let's create our
handle open and handle close functions. So let's do handle open is takes nothing and
it sets the state to open. So open will be true. And actually here as well, we need to
get the details. We need to do this. But let's make this into a function of its own because
we we don't want to repeat our code.

Let's call this set user details to stay Or map
makes more sense. And it takes the credentials because we need them. And here, let's face
this and it. So here, we get the credentials, and we call it with credentials. And here
as well, we need to call it. So let's do like this, I can just pass it this dot props dot
credentials. And it will do the same.

Let's create the handle close. Takes, yeah, it takes
nothing. And here we just say this dot set state. Open, is false. All right. Thank you, this is it. Okay, so
here, we need to, after the button, we need to put our form. But here, let's create, let's
actually do the dialogue. And the dialogue will take the open, the open would be this
dot State DOT open. And is the on close callback or font method, this would be the this dot
handle close.

And I'm going to give it a property of full width, which will make it take forward.
And I'm going to give it a property max width of SM. If you see there's a cool example here,
let's close this, the full width dialog and if you change here, you can actually customize
the width. So I'm going to do the SM It seems the most you know, the one that makes the
most sense, or the one most appropriate or for application. Don't know why these tags
are closing, let's close the dialog. Pretty sure I imported the dialogue. Yeah, did excuse
my text editor guys. Alright, so here we need the dialogue tech title. So dialogue, title.
And this will say Edit your details. And under under here we put dialogue content. All right,
close this one cool form. And here we'll have a form. And but it's not
going to have a submit action because our dialogue actions are going to do that for
us. So here we're gonna have text fields. So I'm going to have text, I'm going to save
text field.

And I'm actually no need to give it some properties. So first, we'll have the
name. So the first will be a bio will have a type of text, have a label of bio, capital
B. And I'm going to give it a property of multi line, which will make it a text area.
Because this is a bio, so we'll need some some more space, and we'll give it three rows.
And let's give it a placeholder. Like they will work like a hint. So here let's say a
short bio about yourself. Let's give it a class name of classes dot remember we have
access to our global theme. So we can do classes dot text field and it will style in the same
way the signup and login text fields are styled. So it will give it a value as well with this
will be this dot State DOT bio. And an unchanged which we haven't created yet will be this.on
change. And let's give it full width. So it takes up the full width. And we close this
as copy it and paste it two more times.

But from these two, let's remove the multi line
and the three rows because these will be just normal text fields. And this will be website.
And the label is website. And text holder will be your personal slash professional.
Professional I can't spell website. This dot State DOT website and same for the rest and
here will be the location so location is the name. The label is location with a capital
L. and here let's say let's just say where you live. And here let's say dot this dot
State DOT location And yeah, that's fine. Let's create the on
change. Actually, it will be a generic on change that we have already written. So let's
just copy it from, from here from the login or from the signup. But did we say this will
be actually let's call it handle change, change, because you want to stick with the same names
that you've used across the same project. So that it makes more sense. So let's face
this handle change here. And we also need at the bottom here, we need our actions or
dialogue actions will be outside the dialogue content.

So here, let's say dialogue. Actions,
which will be the buttons at the bottom of the dialog, and we'll have two of them. So
the first one is a button, and it has an onClick. And this will be the close button. So this
dot handle close. And this will be the button if people want to cancel, let's give it a
color of primary and let's call this cancel. And let's copy it, paste it, this is this
will be the save. So this will be the one that sends the request.

And let's give it
the handle submit, which we haven't created yet. Okay, so we have handled change, let's
create handle submit, will be handle, submit, it won't take an event because it's not based
on a form. Let's do const const, user details equal to get the bio from this
dot State DOT bio. Let's copy this twice. This will be website. And this will be location.
And here we just need to call our function. So this dot props, our action edit user details
and pass it our user details. And here, we actually close the dialog after we submit
so this dot handle close, I guess. And I think this is it for this dialogue. Let's remove
this dialogue text because we don't actually use it. And let's save all files and look
at our app. Okay, map user details to state is not defined. Map user details to state
it needs to go before the other ones.

So that they will know what we're talking about. Oh,
silly mistake, this dot map user details. All right. Let's look at our app cannot resolve
icon edit. Its first of all edit icons. But either I or just edit. Yeah, I forgot the
slash. Alright, so we get the edit button. So let's say I wanted to change London, UK
to let's say Paris, France, and I wanted to remove Hello, um, user and say, I don't know.
I am the user. So let's save loading. Cool. We got the new details. Paris, France, and
I am the user.

But I want this button to be on the right so let's go here under theme.
Let's see button. I gave it class button I think Yeah, we did. So we simply gonna say
float. Right? And we save. Cool. We got our button on the right and it says Edit details
when you hover it and it works just fine. For remove this text we see our placeholders.
Yeah. Alright. So right now if we log in the, the navbar doesn't change, the buttons still
remain the same. So let's actually change it so that when we are authenticated, we have
buttons here to add a post and to see notifications and stuff.

Alright, let's go to our project.
And here in navbar. The navbar now needs to know whether we're authenticated or not. So
it needs to connect to the state. So let's bring in so here let's import import connect
from react Redux. And let's connect our navbar. So here export default Connect, let's say
map state to props. And it doesn't take a mark. It doesn't use any actions. So we just
admit to that argument. And here let's say const. Map state to props takes the state
And returns the following.

So we need authenticated so we can extract only that so authenticated.
That's going to be from State DOT user dot authenticated. All right, let's, let's ram
prop types as well, I might as well. So prop types from prop dash types. And here, let's
say dot prop types. We have authenticated, not state prop types, dot bull, because it's
a Boolean, and it's required. Alright, so here, now that we have the authenticated,
let's extract it. So inside the render, let's say const. authenticated equals this dot props.
And inside the toolbar here, let's cut this, let's say let's do an expression and say authenticated.
So ternary operator, if it's for authenticated, we show something on here, colon, so else,
we show this.

And because there's three elements here, we need to wrap them in a fragment,
so frog meant. And we need to actually import that. So inside of here, let's paste our buttons.
And let's import fragment here, add fragment. and here if we are, if
we're actually authenticated, let's do another fragment here fragment tab. And here, we want
to show three buttons. One, that's actually a plus. So here, I'll do of course, with the
tooltip. We're going to use the same pattern from this button here.

So tooltip icon button.
But actually, there is like a bunch of elements here, let's create a component for this button
that so that we don't actually have to import all these things into our components whenever
we want to use this button. So let's create a custom component in utils. Let's create
my, my button, dot j s, you can call it whatever I chose to call it my button. This is a functional
component. So RFC tab. And here, we can just say export default, like this, and we're gonna
destructor from the props is going to have children. So the way this thing works is that
let's go back here. So the way it works is that it's going to take a tip, so for the
title of the tip is going to take the onClick. And in case we need to style the tooltip or
the icon button, we're going to take two class names for both of them. Of course, we don't
have to have them, but if we do, it's going to style them.

So here, we're going to take
children and children is going to be whatever that's inside. And usually it's the icon.
So we're going to have my button and then we're going to give the props and inside of
that we give any icon and that icon will be will be the children will be rendered inside
the button. So we're going to take an onClick we're going to take a btn class name, which
is going to be for the icon button, we're going to take a tip class name, which is the
class name for the tip for the tooltip. And we're going to take a tip as well, which is
the title for the tooltip. And here instead of doing return like this, we can actually
just do parenthesis, because we don't need to process any logic here.

And here, we'll
say tooltip it's actually important, the tooltip and the icon button. So here import tool.
From art. Yeah, I'd like this material, UI slash core slash tooltip. And we need the
icon button. Material UI, slash cause slash icon button. Alright, so here we say tooltip.
With the title. That's tip, class name of tip class name. But of course, this is, if
we don't give a class name. It's not a problem. It's just not going to have a class. So we
can have it like this. And inside we'll have icon button. We'll have an unclick of on click
and a class name of btn. Class Name button class name. And actually, let's do this because
we're going to have stuff inside of it. And here will be just children which is going
to be the icon. All right, let's save this Let's go to nav bar.

Here, let's import it.
So let's do over here at the bottom here to say import my button. From we go back one level to utils, slash my button.
And here, instead of tooltip, we do. So this will be the plus button my button. And it's
gonna need that, it's not going to have an onClick. Right now it's not going to do anything.
So we just give it the title of the tip or just tip to say, create a scream, or post,
a scream. And inside is going to have the Add button or add icon. Let's say here icons.
Actually, I'm going to bring all the icons we need right now. So we need the Add icon
from material, UI slash icons slash add. And by the way, this is the Like I said before,
this is a default export, you can just have ADD, but the fact that I add icon to it makes
it more readable in my code, I'm like, Okay, so this is an icon.

Or let's copy all of this
as paste it twice. And here, we're going to have Home icon. Here, this is going to be
home. And here, I'm going to have notifications. From notifications, or Alright, here, we're
going to have the icon, the Add icon, so add icon. Let's give it a color of primary. Let's
close this. So that's the first button. The second one is going to be the home button.
So my button and tip will be home. Will we have a class? No, I don't think so. So here
we'll have the icon. So Home icon, color, primary. Actually, this is going to be a link
to home. So let's wrap it in a link. Let's cut that and do link. We already imported
link, let's do two, slash and close this. And inside paste our button.

And the third
one is going to be the notification. So let's say my button with a tip notifications. Let's
close this. And inside we're gonna have the notifications icon, the color of prime primary.
Alright, so with afueras dedicated, we should see these buttons. Let's save. I'm already
running my project. Let's refresh. Oh, actually, the tip is not showing and the color shouldn't
be primary, of course, don't always think in the because it's going to be the same as
the bar. But the way these buttons work, they're actually svgs. So we can actually target them
from our CSS. So let's go to our app CSS. And inside of here, I'm going to say and,
actually, this is not sass to CSS. So I can, I need to say dot nav container. And here
I'm gonna say SVG. So any SVG inside of the container and the nav container, so any SVG
inside of our navbar.

Let's give it a color of hashtag fff, which is white. Let's say
let's go back. Cool. They're white now. But let's fix this notification. This the text
not working. It must be from the button here. So tooltip or title, not title. I misspelled
title. So let's save. Alright, so we got our tooltips. And if we click on a user, and we
click on home, it actually redirects to home. Of course, these don't do anything yet, but
we will fix that. That's actually changed as well the buttons and so in profile here,
instead of this, we're going to have my button so as to my button. And it's going to have
a tip of edit profile picture. And we're going to have an onClick of this dot handle edit
picture. And because this button has a class name, we're going to give btn class name equals
button. And yeah, this is it. And inside the my button will have the edit icon.

Actually,
I forgot something inside the knob bottom, we need to remove this color primaries, because
they're they don't serve any purpose right now. So back to the profile here, we actually need
the color primary. So primary, we closed the icon. Don't know why there's this squiggling.
Okay, it's fixed. So we can remove this. And let's copy all of this. Let's come here under
this tooltip. Let's do so the tip will be logged out. The onClick will be handle logout.
And we don't need a btn class name here. So let's remove this. And this will be keyboard
I keyboard, keyboard return instead of icon, we can remove all this now. And we need to
remove the inputs because we don't need them, because they're already in the button.

And
we need to bring in the button. So here to say, import my button. Oops, button from utils
slash my button. Oops. That's fine. Let's go to the details. So let's remove tooltip
an icon button. And here let's bring in my button. So my button. Again, I did this you
capitalized. So we go back one level slash shooto slash my button. And I think I still
have it copied on I don't. So I could just say my button. And the tip will be edit details.
And on click will be this dot handle open. And we need a btn class name. Classes dot
button. And close this tag inside we have the edit icon with the color primary. Close
this remove this. Let's copy this. So actually, no, this is the only button we have here.
So let's just save all files. And let's check if nothing is broken.

Cool, this still works.
And we get the message where the placement is actually at the bottom. So here, I forgot
to add the placement. So in the tooltip place, placement equals top, as you guys wanted on
the bottom, you can leave as the default. I like the top one. And even here, if there's
no space, it's going to be on the bottom, even though that actually says placement top
and then the other one's going to be on the top. Alright, so now we want to show the like
button and number of likes and number of comments on the screen cards. But one thing I want
to fix is here in the home was the home here. So in the home, we're still using axios, we
need to create an action for getting old screams, we need, we need to create actually a couple
of actions that we're going to use as well in the scream components. So here I'm going
to import some types.

So we have set screams maybe some of them we haven't created yet.
But we will in a second. So loading data as well. Like screen. Unlike screen, I think
that's it. Yeah, that's it from we go back one level, and it's types. Of course we need
axios. And here we needed to do the first one is the one we need in home. So export
const get screens. Equals doesn't take anything and it just first dispatcher say loading.
Oops, we need to use dispatch. So here we say dispatch. And here we say dispatch an
action with the type of loading data like this. And then here we can send our requests.
So axios get to slash screams and we get our result we dispatch an action with the type
set screams and the payload will be the response data.

And here if we get any error we need
to clear out the screams Actually, we don't need to type for this, we can just dispatch
type will be the same actually set screams and the payload will just be north. So just
reset them back to No. Or are actually empty object, well, this will almost never happen
but, you know, you never know. Alright, so let's put some comments here, let's say get
all screams and now we're going to create the, like a screen, okay? So like a screen like this, let's say on like
a screen okay here in the types, let's create these new types. So what do we have we have.
So we have set screens loading data like screaming, unlike screen. So these are all data types
or data reduce the types. So here we say const or export const, set screams equal set, screams
not scream set screams we actually need another one for way later forgetting one screen that's
called just set screen without an S. We need us control D here and do like screen.

We need
unlike screens or control the on oops, unlike screen. And what else we need loading data,
which is going to be a UI thing. So here we paste, select this control the loading data
thing this is it. Yeah. Okay, let's do the other actions as well so that we don't have
to return to this file. So export const like scream. And this will take the screen ID of
which screen to like, we'll take this batch. And first thing with dispatch to dispatcher
loading No, actually, we don't. Let's do axios dot get and do template string slash scream
slash dollar sign curly braces scream ID slash like. And then forget a response. We dispatch
an action with the type like scream, like screen. And the payload will be rest data
because we're going to get the like back. and here we can see catch. We have any errors,
we actually just console log them.

Console log error. All right. Unlike scream I think
is almost the same. We can just copy and paste it here. So unlike screen, it takes the ID. And it does the same a sends a request to slash
scream slash ID slash on unlike. And here we get the data we dispatch a type of unlike
scream. And yeah, it's the same. So it's good like this. Alright, let's go to the data reducer.
Let me close the console window actually is taking up unnecessary space. So we need some
types of set screen. When it actually screams we need like screen. We also need unlike screen.
What else loading data? Yeah, I think this is it for now. So types, and we need to initialize
to do an initial state variable which will have screens. So this will be the array that
holds all screens whether in the homepage or in a user's page. And we have a singular
screen, which will be one we want to see just the details of one screen and we will have
a loading as well.

She's initially set to false so export default, whoops default function
that takes a state which is equal to the initial state initially and an action switch. Same
thing as the data reducer. So action type. And here first, let's take care of the loading
case. So loading data before loading, we just return types of return, we spread the state,
and we set the loading to true. Next case will be the set screens, set screens,
we return spread the state. And here are the, we set the screens to what we get.

So action
dot payload. Remember here, if we get the screens here, the response to data which is
in the payload will have the array of all the screens. So we do screams action, not
actions action dot payload, and we set the loading to false. So next will be the like
scream. So case, like screen. So in this case, what we want to do is let me look at the Redux
here. So what we want to do if we go to Redux, we go to our state, the way we determine whether
we like a scream or not, we look at the likes array.

And here, what we want to do is that
if we like a scream, then we add that like to this array here, for the user. And we also
add the number of the soda, the light count, let's say the screen has a light count of
two, we add three to it. Or actually, no, actually, we get the entire screen back once
we like a screen. So we just need to find that scream in the scream array. Or is it?
Why don't we have screams here? Or because we didn't actually have that we don't have
that reducer yet. What am I saying? So when we have the scream array, we will add the
number to that screen, you'll you'll see, when we start testing it. I should have explained
that later, actually, but whatever. So let index. Now we want to find the screen. So
let's say State DOT screams dot screen dot find index, we need to find the index in the
array first. And here is a higher order function. So this scream, we want to find the screen
that has the scream dot scream ID the same as the one we got back from our payload.

So.
So if remember, when we like a scream, we get a screen, we'll get to that screen back.
And then now we have to find it an increment, it's like count. So now we get the index of
it. And what we do here, we do state and dot screams. And now we use the index equals action
dot payload. So we replace it in the state. And now here as well we do state and for the
unlike screen, actually, actually is the same even when we are like we get a screen back
with the different, like count. So we can we can do this we can chain unlike scream
like this. Yes scream like this. And this will that means in both cases do the same
right here. And we need as well to handle like scream and unlike scream from the user
reducer as well.

So here, let's import the type. So like ups, like scream. And here. We do case, like and
here they are actually different like screen. Here what we want to do, we want to add to
that like so we can have this cap keys annoying. Alright, so we return the state
as it is. And here in the likes array.

We return an array and we spread State DOT likes.
And we are the new ones. So here we add a new like and it will have a user handle just
like the other likes, would have the State DOT credentials. Because it's this user so
we can use the handle from the end it will have a screen ID of the same screen ID of
the screen that's returned from the pay in the payload because after all, we return the
same screen from our server or from our Cloud Function.

And here let's see case. Unlike
screen Now here's different, we just need to remove it from that array. So here we do
return return, we spread the state. Here, we do likes, equals State DOT likes dot, we'll
use filter to remove one of them. So here what we need what we need to do we say like,
so we filter out any like, which has a scream ID, which is equal to the action dot payload,
dot scream ID. Alright, so we're done in the reducers.

Now we need to go to our screen
and actually show this like button. So here, we need to actually reconnect our home. Actually,
we need to connect our home. So here, let's connect our home first. So here import, connect. From react, Redux, we need to get the get
screams. From Redux actions, data actions. Let's get prop types. And here, we need to
connect the home. So Connect map state to props. And here we have only one action so
we can put it here. So get screams. And we wrap this home in parenthesis, and here we
say const. Map, state to props. Takes the state returns the following. So we need we
need the data. So data is state data. Remember, this is our reducer our data reducer puts
all the data in this data object. So we need to get this in the home. And we need to do
our prop types.

So home prop types equals we have our get screams she's a prop ups prop
types dot funk is required. And we have data, which is a prop types.object.is required.
All right, so here, we don't have a state because we're going to get them from the props.
And here when the component mounts we just need to call get screams asexually get screams
not get scream here. And Yep, that's correct. And here we get in the render. We get our
screen screens rather. So from data we get. Or actually we can do like this. So screams
and we need loading as well. equals this dot props dot data. So here, we do. So we check
we don't check the screams we check the loading.

And here we do just screams like this. And
we don't need this parentheses actually. And here we don't need these parentheses as well
because it's one element. All right, so this should fix the home. And actually our app
is crushed so like scream is not exported because we didn't save save here as well.
assignment for function call is that homeland 14 home Oh, yeah should call the function. Data reduce
action is not defined and stay is an undefined Yes. So Oh, here it's state and action. or
his action not actions. Yep. Okay. Okay, unlike scream is not defined in user reducer. Because
we didn't actually bring it in. Or I didn't bring it in. Come on. This time it works.
Oh boy. Data return undefined during initialisation. Oh, because we don't have a forgot about the
default actually. This switch default case So default would just return state. All right.
Okay, this is loading. Let me reload, just in case seems to load forever. But if we check
the state, we actually have the screams. So must be some problem with the logic here.
Oh, actually, no, if we're not loading then show the screams.

Alright, cool. So again,
the screens, everything works fine for home nuts. Now let's take care of the likes the
like button. Now here and actually, first let's connect to the component. So here we
connect from react. Redux. And we need like an unlike so like, scream,
and unlike scream from Redux actions, data actions. And let's get
prop types. While we're here. Okay, so here, let's do, let's cut this and say Connect map
state to props and map actions to props. And here, we just paste that here, let's say const.
Map state to props, equals takes the state and returns we need the user not the state
to use a map map actions to props oops actions to props
for now, just the two that we have.

So like scream and unlike scream and we do the prop
types. So we have like screen is a prop types function that is required. Let's actually
copy this oops, hurts just unlike and we have user is prop types.objects.is required. We
have scream, which we actually have been passed here this one prop types.object.is required. We have classes
because of with styles. Alright. So here after after the body, I want to put we it's going
to be we're going to depends on our authentication state, we're going to create a different like
button so like button, as well whether we'd like to scream or not and after the like button
or put a spawn with the number.

So here we'll have like, count and says likes here. So the
number of likes next to it the word likes. And so while we're here, actually we can put
the I need to bring in my button, we can put the comment ones as well. So here we have
a tip that will say comments. And actually doesn't have any doesn't do anything. But
here we'll have a chart icon which I need to bring in as well with a color of primary
color.

Primary. Yep, let's bring in this actually is actually as well after this is to say how
many comments there are. So here we say comment, count and space comments. And so we need to
bring in my button and shut chat icon. So here is to import my button from utils
slash my button and what else the icon so here let's A icons.

Here let's actually Redux space here we have
import shot icon from material, UI slash icons slash, shot. And here this, we need to create
this like button. And the way we're going to do this is that we need to actually find
out whether the user, this user that's logged in, has liked this screen or not, too. So
I'm going to use these two icons. So if the user has like the screen, you see this filled
heart, if not, you see this empty heart. And as well, if the user is not logged in, you
see this empty heart. But when you click on it, it redirects you to the login page. Because
you're not logged in, you can't like screen when you're not logged in. So here inside
the component, I'm going to create a function called liked screen, which will tell us what
whether we've liked this screen or not. And it takes a scream ID. Actually, it doesn't
need to take the scrim ID because it only works for this screen. So it can do like this.
And it checks if, first of all, we need to check whether we have a likes in our user
object.

Because if we don't, that means we don't even need to check it's false. Is there
is no like there if there's no like array. And of course, if we don't, yeah, okay, let's
do this dot props. I don't know, I was gonna say that, and then I'll stop. likes. If we
have this array, and that and this array as well has this screen. So we do this dot props
dot user dot likes, and we're going to need to use find the D array, higher order method
or for forgetting, like, so we need to find a like with the like, with this scream ID.
So which equals to this dot props, dot, scream, dot scream, ID, because remember, we have
this, this screen, we have it passed down from the home.

So this condition, find returns
undefined if it doesn't find anything. So if it doesn't find one, the condition is false.
So here if it's if, if it's if this is the case, then return true. Else. return false.
always save. So this will this will check if we've liked the screen or not. And we'll
have now two functions for like methods for liking and unliking.

And by the way, if you're
wondering why I'm like saying method instead of function because we're inside of a class,
technically, a function that's belonging to a class is called a method, because it operates
on that class alone. So this dot props dot scream, yeah, we just use the slike scream,
and we pass it the ID. So that scream Id let me just copy this because unlike is almost
the same, but we just changed this to unlike scream, you change this as well.

Alright,
so here, let's create this button. So inside of the render, let's say const. Like Button
equals, now we're going to have two ternary operators. First thing is we're going to check
if not authenticated. Actually, we need to get authenticated as well from the props.
So here in the props, we have the user because we mapped it from the state. So we do user
from the user we get we get the likes, don't think we get the likes we get authenticated.
Think we only get authenticated. Yeah. So if not authenticated, then what we need to
do is we need to show a button, my button. Tip also, like and inside of this button,
we're gonna have a link.

I'm not sure do we have it? Yeah, we we have link important so
link to slash login. So if we're not logged in, it's gonna redirect us to login or we're
gonna use favorite icon or fav not actually is the owner be the empty one. So favorite
border. So yeah, this is called favorite border and the other one is just favorite. So we
show favorite border with the color of primary. And yeah, we close this. It's actually important
those two icons so we can just copy This. And here, replace chart with favorite, because
I want to call the favorite one favorite icon, spaced again. And here, Alt and select these
two and say, a favorite border. Alright, so now we have to both the icons, we can use
them. So yeah, if we're not logged in, we show the empty heart and we flick off, click
on it redirects to the homepage, I mean to the login page. Else, if we are logged in,
we need to do another check now.

So our check would be this dot liked scream. Oh, actually,
I called it scheme apparently. So like scream. So like screen. So now if it returns true,
that means we have liked this screen if it's in our likes array. So we need to show a full
heart. So here we say my, my button with the tip. Now because we've already liked it, the
tip should say undo like, and we're going to have an onClick for this. So on click will
trigger the this dot unlike screen.

And yeah, we're not going to have any classes. And here
we're going to have the favorite icon with the color of primary. And here, let's copy
this. Else. So if we haven't liked it, we show a button with the tip like and it triggers
like scream. And the icon here would be favorite border. So favorite border. All right, let's
save all of this. And let's, let's see if this is working. So let's go to social ape.
And there we go. We've actually apparently liked all the screams, look at our status,
put them side by side like this. First of all, let me log out. And yeah, we get an empty
heart. And if we press on it, it redirects us to login as login. So user at email. COMM
123456. So here we have three likes, we've liked all the screens, and if I unlike this
Hmm, there's something weird with these.

Oh, okay, so it's removing the wrong ones. It's
removing the other ones instead of removing just that. So think, okay, so in the US, okay,
here Yeah, if I unlike a screen, it should filter out the one that is not equal. So it,
it should just leave the other ones that are not equal to that one and remove. So filter
filter removes these one keeps these ones not removed, this one's okay, this should
fix it. Alright, so if I refresh, if I like, call, it shows the number and if you click
on like scream and click on difference, that's what it did it incremented the light count
of that scream in the screams array. And added dislike to our users like array.

And it will
do the same here to like, click here different shows you just the difference between the
stage and the last stage. And if I unlike this, the unlike screen action, yeah, decrements
the light count here and removes the like from the likes array. So let's now add a delete
button for deleting our screams. Alright, so in the scream.js component, let's add the
button under the handle right here. So under the typography that's got the handle, actually,
it's gonna depend on a couple of things. So let's do here, delete button. And let's create
this delete button. object. So here, let's say const. Delete button equals, and this
is going to depend on whether we're logged in. And whether we are the owner of this screen.
We don't want to show a delete button on this screen because it's not users scream. We're
going to show the button on this and this and this one.

Alright. So here we say, authenticated.
So we need to make sure that we are authenticated. And user handle, which is the handle of this
screen, the user handle of this screen equals, actually, we need to bring. So from here from
user, we need to bring in the handle of this user, the current authenticated user. So it's
inside of credentials. So here we do credentials. And from credentials, we destructor, the handle,
which is handled. And so here, let's say how user handle equals handle. And here, let's
say render this, or actually, it's a ternary operator.

Because if it's not, we need to
say no. So it doesn't render anything. So here we, we need to say, we're going to create
a component for this with let's call it the lead, scream, like this. And actually, we
need to pass it the scream ID of this current scream, because the Delete, scream component
will not access any data from the state.

So we pass it a scream ID of this scream ID that
we already have of the screen. So let's create this component. So here, I'm going to create
the lead scream, dot j s, let's do our sea top, remove this export. And let's bring in
some of the imports that we have here. We're going to need us just copy all of this, we're
going to need fragment I think we're styles, I don't think we're going to need link or
none of these, actually, I'm gonna need my button. And I'm gonna need some stuff from
the from movie. Actually, because this button is going to open up a dialog. So let's import
we need button. Because the the option, the dialog actions are going to have buttons.
So t y slash co slash button.

Now we can just copy this, paste it three more times. Here
Ctrl D, we need dialogue. Control the dialog title. We also need dialogue actions. We need
the icon the Delete icon, which is called delete outline, you can also use the Delete
which is full icon. But I prefer the the outline one because it doesn't. It doesn't distract
too much from the screen itself. You don't want to emphasize the delete button in your
design, so slash actually slash icons, slash delete.

Outline. All right here, let's bring in Connect. Because
we need Actually, we need to create the the action for deleting a scream. So let's import
delete, scream from Redux slash actions slash data actions. Let's go and create this. So
here at the bottom, let's say export const. Delete. screen, it's got to take the screen
ID.

We need dispatch. And here we're not going to do we're not going to dispatch a loading,
we're just gonna send a request axios to delete to backticks, slash scream, slash and we concatenate
the scream ID that we got passed. And here we say dot then we don't need what's written
in the result. There's nothing there's just a message.

So here we say we dispatch a action
with a type, which we haven't created yet. Delete, scream. And the payload is going to
be the scream ID that we passed to the to the function, this one. So here, I say dot
catch. error, we just console log it. This is it. Let's actually copy this delete screen.
Important from types and let's create it and types. So it's spot of the data reducer. So
here we say, export const paste Delete screen equals a string delete screen. Let's go to
data reducer, or data reducer. And here, we handle the case. So let's say case, delete
screen. Because the way this is gonna work is that what we can do, we can as well delete
the scream and then call get screams.

But I don't think that looks good. Because if
you delete a scream, and then you again, show that all screams are loading, it kind of gives
away that you're actually fetching the screens again. And plus, we actually send an extra
request. And that's not necessary. Because the fact that we get a response here, that
means that the screen is deleted, we can just delete it from the local state because we
know that it's deleted on the server. So what am I doing this custom data data reducer,
and here, we just need to find the index of that scream and remove it from screams. So
here, we say, we can use the same index variable from here, it's already declared here, say
index equals State DOT screams, dot find index.

And we need to find the index of the scream
that has a scream dot scream ID. That's the same as the action payload. This is why we
passed that scream ideas action pedal. And now we say State DOT screams, dot splice,
which removes which removes elements of a an array starting from one index, which is
the index and a number of them, which is just one, we just remove that one. And here we
do return and spread the state. Alright, so the auction is done. Now we need to create
the component. Let's connect this and actually let's initialize a state's const styles rather,
object. And here, let's say let's get this let's say, export Connect. Map state to props.
And we need one action, which is the Delete screen. And here we connected to with styles.
We pass the styles.

And for the second one, we pass the component. So here let's do const
maps date the props. Actually, no, we don't need anything from the state. So we don't
need a map state to props. so here we can actually just pass No, we just need the action.
Let's create our prototypes. So delete, scream, dot prop types, equals, we have the delayed
scream function. So prop types.funk.as required.

We have classes prop types, dot object that
is required. Quiet. And we have the scream ID that we got passed down from from our scream
called scream ID prop types.string.is required. All right, so let's create our component here.
Here in the render, we need our classes const classes. This dot props. Here, let's do return. Wrap
everything in a fragment. So here the first thing will be the button that triggers this
dialogue to open. So my button with a tip. Let's say delete, scream, actually with space
in between. and the onClick will be this dot handle open and the btn class name. Do you
need a btn class? Yeah, we do we need to style this. Let's give classes dot delete button.
Actually not like this. So we close the button like this. And inside the button we need to
have the Delete icon. So delete. outline with a color of secondary wanted to be red because
it's the delete button.

Let's create these handler methods. So actually we need to set
the state as well. Because this we need an open very an open Boolean which is false by
default, we need a handle open. She takes nothing and does this dots setstate. Open
true. And we can just copy this and say handle close. Sets date open to false. And we need
as well.

One called delete scream, which calls the function as the action this dot props
dot delete screen. And we pass it this dot props dot scream ID, which was passed down
from the screen. So where are we? Yeah, this one right here. So the scream ID, we passed
it here. And then we set the open to false. So once we delete the screen, we close the
dialog. Alright, so under the button here, we actually do our dialogue. So dialogue.
And this will take a while we have yet to open, which is going to be this dot State
DOT open.

And the open close, which is this dot handle close. Let's give it a property
of full width. Because I want to specify the width of this and give it max width. Small,
SM, close this. And here we will have a dialogue title. And the dialogue title will simply
say Are you sure you want to delete, oops, delete, I hate the word delete the scream.
And you can as well add like a body that says this action like in between brackets like
this action is not reversible, or guys like Feel free to customize what we're doing. Don't
like if you want to add something you can. So experiment all you want, I actually recommend
that you learn a lot by doing that. So we have now actions, we need to do our actions
which are two buttons, one that cancels, which closes and one that says delete, which actually
confirms the Delete and calls this delete, scream and closes the dialog as well. So the
first one will be button on click. This is the cancel. So it's going to trigger 100 clothes.
And just give it a color of primary.

Yeah, that's an inside the button it will say cancel.
Or we could just copy this and add a second one that says delete. And we'll call delete,
scream. And the color will be secondary. We want it to be red. And I think this is it.
Yeah, this is a you had the thing. Oh, we need to style this button. I want it to be
so I want the button. Scream is on the phone and Data Register because we didn't save or
think or did we not? We didn't import it. So delete screen like this. Where's the up?
delayed scream is not defined. It is. So in scream delete. All I didn't import my bad. So here are the top, say import, delete scream
from delete screen. All right.

Okay, cool. So we get the button on this right here. But
let's actually test this. Let's delete this another one. So we get a dialog that says
are you sure if we cancel it closes the dialog. And if we click again, it opens it. If I click
Delete, it's gone. And it's removed as well. Instantly from here, cool. But I want to place
this button right here facing the user. So let's do so here let's add this delete button
style. and here we can say left 80% or actually as a string 80%. We need to give this a positive
position of absolute. So you can move it around. So absolute cool. Let's save look at it. Or
is it actually it's right here. Oh, actually, we need to give the court a position of relative
so that the absolute on the button could work.

So here in the card. Yeah, this here Let's
put it at the top, let's say position puts session of relative. Now it should this absolute
and refer to the card. Cool. And it does. On let's let's set it right here, actually.
So inspect this. And this button would be, yeah, this button right here. Let's remove
the left because I want to align it with a some of the left for now. And then other top.
So I want to align it exactly what the user here. So say top 5%. Actually, a bit more.
Yeah. 10%. And then actually, the left should be maybe like 90%.

As to 90. Yeah, perfect.
It's, it looks much better like this. Alright, so here in the Delete, say left 90%. And then
top of 10%. That's safe. Cool. We got the button on the may remove the inspect window,
and we got the button and it works. we delete this yet another one works. Cool. All right.
Yeah, by the way, guys, I will put a link in the description for the get get repository
for this for all this code. And let me commit right now and show you how I've been committing
this. Let me clear. So git add git commit.

This is what part 24
I think. Yeah, it's part 20 as part 25, Part 25. Alright, so git log, let me show you how
you can actually. So what does this get? Log? Yeah. Okay, so part
25 right now. And if you have, let's say you're stuck up, but like 22, or something, you can
just do a git checkout and take this. So it's like, zero, a, two, five, or is that two zero,
F. And here you have the code that exactly part 22. And I only recommend you to get the
code if you're actually completely stuck.

And you're like, what the hell, I typed the
exact same code, but mine doesn't work in his works. You can just compare against yours.
So that you see where you actually type something wrong or something like this. I mean, go back
to go check out master. Yeah, so I will put a link in the description for the for the
get repository for this code. So let's add some functionality to our post Screen button
right here. So I wanted to open a dialog. And then in that dialog, we type our scream,
and we press submit, and then it shows it right here.

Here, let's create a new component,
call it post scream, dot j s basketcase, of course. And here in the navbar. Let's replace
this first button. Yeah, this one right here. Let's say post scream, close the tag is removed
the Add icon, we don't need it anymore. And here, let's import the component we just created.
Suppose scream from same level post scream. Alright, we are here. So this one is going
to have a dialogue, it's going to need a bunch of things, very similar to the Edit details.
So we can actually copy all of these and then edit it. So let's bring the Redux stuff down.
I prefer to have it at the bottom. And we need Redux react component fragment prop types,
all this stuff we need. We're not going to need auctions. I mean, remove auctions. And
instead, not instead, we also need the circular progress. So So killer progress. I want to
show a spinner one we are sending our request, cemetery UI slash core slash circular progress.
All right, we don't need edit user details.

Instead, we need post scream from data actions.
And we need to create that in a moment. And here we say class, post scream, extend extends
component. Here let's do export. Default Connect. We're gonna have a map state to props. And
we only need one action. So let's say here inside this object post screen, we cannot
get with with styles and we pass it styles and the second parameter Is our component
post scream here, let's say const styles. Let's leave it empty for now. Let's do our
prop types. So post scream dot prop types. Here we have post scream. Prop types
dot funk is required. And we're going to need the UI. So say UI, prop types, the object that is required to
map state to props const map state, to props equals takes in the state, and returns the
following. So we just need the UI. So UI is state.ui. Okay, before we carry on, let's
actually create the auction.

So let's go to data auctions. And here, I'm going to put
it under the get screen, let's put a comment, say post a scream. And here, let's say, export
const. Post scream, it takes in new scream in his dispatch, as well, so we go through
dispatch. And here I want as well. So we got that loading spinner, we want to show some
loading. So let's dispatch a an action with the type loading UI.

After that, let's do
our axios call. So axios dot post, to slash scream. And we pass the new scream as the
data. So that then when you get a response, here, we're going to dispatch a new one a
new type. So this will be type, I'm going to call this post screen. And the payload
will be the response. So restaurant data, which is going to be one screen. And here.
Actually, let's do the catch first. So it would make sense. Because we can get some
validation errors, if you remember, we could have an empty body and it will say like body
must not be empty. so here if we get an error, we need to dispatch set errors. So type set
errors, and the payload is. So error dot response dot data. And here Actually, let's dispatch
a clear errors, just in case there is some errors. So type is clear. errors.

Let me make
sure everything is fine. So your post screen restaurant data, will dispatch clear errors.
Okay, everything is fine here. And let me make sure we brought everything. So we need
post scream, which, which I think doesn't exist yet in the types. So it's set errors
and clear errors. And yeah, loading you Why do we have loading UI, we don't loading UI.
Let's go to types and create the ones that we don't have yet. So for data, we need to
say export const. Post screen equals post, scream. And we need loading UI is created
set errors, we need clear errors.

So let's say export const, clear errors equals clear
errors. All right, so now we need to go to the data reducer and change the state accordingly.
So here, under here, we say case post screen. So okay, let's bring in the type as well and
actually both screen. so here if we get a scream, we need to add it to our to our screams
array. So here we say return the state as it was. And in screams, we're gonna, we're
going to actually put it at the top. So because it's the newest one, so here we do action
dot payload. And then we spread the rest of State DOT screams. Alright, so we're done
here. Let's save everything and let's go to our post screen and created. So inside of
this component, we're going to have a state we have a dialogue. So we need the open So
initially set to false, we need a body for our screen, which is empty, and potential
errors that we can get, which is an empty object initially.

So here we need handle open
and handle close. Doesn't take anything, just this dot set state to open to true. Let's
copy this and do the same for clothes. We're not the same, but we just change the value
of open to false. All right, here we are, let's do our render, render. Let's get errors
in case there's any from the state, oops, this dot state. And let's get our classes.
And we also need the loading from UI. Actually, we need just the loading. So what we can do
here, we can do in map state the prospect to say loading, oops, not like this loading.
And it will be Yeah, we need loading.

And here we'll say loading as well. And it will
be the state.ui dot loading. So we get just that. Actually, no, nevermind, I'm wrong,
because errors is stored in there. And we will need errors as well. Oops. Okay, so from
UI here, we need loading. And here, we get these from this dot props will return gonna
have a fragment that's gonna surround everything, and first is going to be the button that triggers
this. So my button is going to have the onClick of this dot handle open. And the tip, oops,
the tip will say, post a screen with an exclamation mark, because it's screaming, of course.

And
here we'll have a an Add icon with a color of primary. Or will it be a primary? I don't
think it's going to be a primary because it's going to be blue. So we just say Add icon.
And let's bring the icon. So here, let's do import Add icon from material, UI slash icons
slash add. Here, we're going to have our dialogue. So dialogue. And here, we need a What do we
need an opener? This dot State DOT open, we need an on close. She has this dot handle
close. Let's give it full width, and a max width of SM. All right, here, let's stop. And let's say what do we
need, we need a title first. So actually, I'm going to put a button First, I want to
put like a close button on the top right. So let's say my button. And this will have
a tip that says close. It's just I just wanted to show you like you can do this as well.
I can do a Cancel button.

But I just want to show you this style as well as have some
variety. This thought, yeah, this close button as well has handled close when you click it.
So it closes the modal oops, close the dialog. And let's give it a class name because we'll
need to style this. And what do we call this? classes, close button. And inside of here,
I think there is a close icon. Let me check quickly. Summary docs are shiny the material
design. Yep, close, so it's going to be just close.

So let's copy this and select our then
Ctrl D and do Close, close icon. So here is a close icon without any color, leave it black.
And here under the button, we need our title. So dialog title. This will say post a new
screen. And under here we need our dialogue content. So dialogue content. And here we're
gonna have a form Say on submit equals this dot handle, submit, haven't created yet. But
we will in a moment, here we'll have a oops, what is this? Here we'll have a text field
with a name, body type of text label of what do we say scream.

Because why not? We're gonna
give it multi line because this is going to be a text area. Let's give it three rows.
So rows three, give it a place holder. And that's a, I don't know, scream, scream at
your fellow friends, or apes, since this is social. And of course, we need an error. In
case there's any errors. And here, the error is the the errors dot body, if you remember,
we have that in our validation. So actually, inside the expression, we say, if it's true,
then the true else false. Alright, so here helper text, which will show the error message.
Text like this. And this will say we'll have errors dot body. Of course, if it's undefined,
we're not going to have any text. And here, let's give it a class name of classes, dot
text field, the global text field styling that we have classes, actually, to use the
global styles, we need to take in our our theme sort of theme. And return this and then spread the theme
here.

So that we can use the global styles. What's wrong? All because this is not close. Okay? Think
this is it, actually, when you're not the on change, on change. And we'll say this dot
handle change. Say full with Yep, that's it. That's one beefy textfield. Here, we'll put
a submit button. So button. And it's gonna have a type of Submit. variant of contained
because that's the style we went with, we'll continue with that style, a color of none
other than primary.

Just give a class name of classes that Submit button. A disabled gonna
do the same thing like the signup form. And the login as well disabled on loading, unloading.
And inside the button, we're gonna have the circular progress. So let's say sir, killer
progress. Let's give it a size of 30. I think the size does matter. Actually, as long as
it's inside something it's going to be it's not going to be bigger than it but you can
experiment and find out. Skip this the progress spinner class, because we need to make this
we need to give it the position of absolute and give this the position of relative so
that this would be centered within the button.

Okay, so Oh, yeah, the button is to say, Where
are we? So here? Inside the button, we need to say Submit. Yup, I think this is it. Oh,
actually, what am I saying they're circular progress should only appear if we're loading.
So here we do an expression I cut it actually and you say loading and and not this and and,
and do parentheses and put the circular loading inside of it. Okay, so here and the styles.
Let's style the the submit button. I give it Submit button you met Yep, submit button.
So here let's give this a position of relative and the progress spinner. Give this a position
of absolute and all the close button as well. We need to give
the close button position of CIO position of absolute Unlike absolute, left is given
90% was 90, something like the delete button, guys. And the top. Let's give it 10%. And
I think yeah, this is it. Let's see what this looks like. Just make sure we don't have any
errors. And we do of course. Oh, we already had clear errors. And we removed that.
Yeah, I don't know what that post screen was so stopped and run again and it didn't happen.
Okay, so source selector is not a function.

Okay, I added a pair of parentheses here by
mistake. Okay, so for click on post screen, it opens up this modal call this dialogue.
And if I submit, okay, reloads the whole thing. Oh, of course, forgot, right, the handle submit
function, and the own change as well for that matter. So handle change will take the event.
And here we'll say this dot said state. So we have event dot target dot name. And we
set it to event dot target dot value for the handle, submit, submit to extend the event
to event dot prevent fault. And here we use the post screen action so this dot props dot
post scream and we pass it this object with the body.

This dot State DOT body. Alright,
let's save. Let's check it out. All right, this is our like dialogue. This is the close
button. If you click it, it closes it supposed to scream. If we actually leave it empty,
we send we don't get the errors. And it shook state roll. We do have an hour. Okay, I need
to do use component will receive props and assigned error. So component or receive props.
Next props. And here let's check for the error. So if next props.ui dot errors, we do this
dot set state errors is next props.ui dot errors. All right, let's check a gun. So if
we tried to send an empty call get an error. And if we say hello, and we click Submit,
okay submits it. And we see which is cool, but it doesn't close the this what we can
do here, but we still have the errors, what we need to do is that we need to check if
there is no errors.

And the loading has stopped. We actually from the component received props
close the handle, mean close the the dialog so we can say here if not next props.ui dot
errors. Because we clear the errors on success if you remember from the action. And next
props.or we could just say and not oops. And not, not. Next props.ui dot loading. So if
this is the case, this dot set state actually lets as well empty the body because otherwise
if we open the dialog again, the body will have some text.

So we put the body to an empty
string. And we do this dot handle close. Yeah, which will as well. The handle close was well
clear. Actually the handle close should clear the error. So here, we say we said open to
false. And we set the errors to an empty object because if we don't, we're still going to
see the errors. Okay, so here we get errors and we close it.

Yeah, we don't get the errors
anymore because we cleared the errors once we close it and if we submit now a new one
I don't know why I saw that error for a second. All because there was already errors in the
state, maybe I'm not clear on them properly. Okay, so we're submitting screens. Cool. So
it works.

And it instantly shows them here as delete them. Yeah. So yeah, we're done. A couple of things I want to edit about this
model this dialogue quickly. This button, I want to align it exactly. Okay, let's put
them side by side on align exactly in front of the title. So let's go here. Let me remove
the left so we can align it let me adjust this. Okay, so 6% seems decent. And 90, or
maybe like a bit more, yeah, 90. Yeah, 91. I also want some margin between the submit
button and and I want to put the submit button on the right side as well. So six and 91 that
added these values. So here, yeah, the left is 91. And the top is six, and the button
on a given a property of float right. And some margin. Top think tanks should be fine.
Let's save slick our app. Hope. Yep, the reloads. Okay, reload the gun.

Alright, there we go.
Cool. It looks much better. Now. I like the button on the side. One problem with this,
though, that I didn't fix last video is that if I click Submit, and there's some errors
in the state, and I close, these errors are still in the state. So if I click here, I
don't see them, because we only received them using component will receive props, by file
type something and I would submit will quickly see the error. And then it submits. That's
not. That's not very cool noise. Let's fix that. So in the data actions, I'm going to
create a function, let's call it export const. Let's call it clear errors, which does just
that it doesn't take anything we it goes through this patch. And it dispatches the action with
type clear errors, that's it just clears the errors essentially. And yeah, we have that
type. So here, when we get when we close the, the when we close the dialog, we want to clear
the errors as well, just in case.

So we aren't clear errors here when we close the dialog.
So let's bring it in as well. So clear. errors. Let's copy it. Let's add it here in our map
actions to props. And let's add it as a prop type. And it's the same as this we can copy
this colon and paste this. And let's Oh prop types not rock types. Let's save. Oh shit, I didn't mean to open that. Alright, failed
to compile clear errors is not exported or because I didn't save all files and save all
files. We go Okay, so we open post the screen will close it. Whoa, what is this maximum
update depth exceeded there must be like an infinite loop or something. So handle clothes.
So setstate under clothes and unclear ORS. Hmm. As no UI reducer, so clear set loading false,
or is No.

Oh, I see. There's an infinite loop here. Because whenever we call handle close,
it calls clear errors, which sets the errors to know and loading to false, which triggers
this again, which triggers handle close. So there's like an infinite loop. So we can solve
it by here, instead of calling handle close, we can manually close without calling this
function so that it doesn't loop. So we can just give it this. Actually, you could just
copy this stuff over here. So yeah, we can close it without calling handle close, which
shouldn't have an infinite loop. So if we open here, and we close, cool, it doesn't
bug out. And if we type something and we get an error, oh no, no, we don't get nearby.
Alright, so if you get an error like this and we close it.

Now we shouldn't get an error
once we submit. Cool and we don't nice, the errors are being cleared once we close the
dialog All right, let's actually start working on the on the button that let us expand our
screens and see all the details of one screen. Alright, let me close this dev tools. Let's
go. Here, let's create a file called screen dialogue. Actually, let's start by creating
an action. Because we're going to need the action that gets only one screen with all
the details. So here, let's add data actions. Let's export const, get scream without s,
so singular, and we pass it the scream, Id need this patch as well.

And here for loading,
I'm going to use the UI loading and not the loading that's inside of screams or inside
of the scream. Yeah, the data reducer. So here, we dispatch an action with the type
loading UI. And here we do axios dot get template strings slash scream, slash, we pass it that
scream ID. And here, we do that, then I get a result. And we need to dispatch a new type.
Summon to enter the type set screen without an S on imports that automatically and the
payload is the rest of data. And here after we need to stop loading, because it doesn't,
nothing changes the loading from the UI to false if we don't do it manually, first. So
dispatch type stop loading UI, which we haven't created yet. And here we have any error. We
What do we do, we just console log, I guess we'll never have an error unless our databases
corrupt or something.

So let's go to UI reducer and handle the stop loading UI. So case, stop
loading, slow loading UI. Here, we just return the state as it is. And we set loading to
false. So the opposite of loading UI, basically, let's copy this. Let's go up here. Let's import
it, as do the same in data actions. Let's go to our types. And we have set screen, we
only need to create the the stop loading UI, export const, paste, and paste again. Alright,
let's go to our to our scream card. And here, let's import our scream dialog.

Import scream,
scream dialog from the same directory. And let's put it at the bottom. Right here at
the end of the chord content. So screen dialogue, we're gonna pass it the scream ID so that it uses that to fetches the screen
so that it knows which screen to get. We're gonna pass the user handle which we will need
way later. Use a handle.

Alright, we're done here. Let's close this. Let's close all of
these. We don't need to use them anymore. Let's save this and close it. Make sure we
don't have any errors we don't cool. Here, we're going to need a bunch of things similar
to what is it to post screen. So let's take these, paste them here. We're going to need
de j s as well to show when a screen was posted.

So import day j s from day j s. We're going
to need link to have a link to the user that posted this screen. So no react user what
react router DOM and here we're going to need a bunch of material UI stuff which is let's
let's copy from the the post scream this stuff the dialogue stuff. We need a copy from here
to here. We don't need to add icon. So instead, we can just put a common a common saying icons.
And here we need the grid, because I'm going to split the card into two sides, one side
has the picture on size has the details from material, UI slash core slash grid. And we're
gonna need typography, of course, typography. And we're gonna need the Redux
stuff. So Connect, and we're gonna get scream. Let's create an empty styles. Array object
for now, let's say class. Scream, dialog, extends, component. And here, let's do the
prop types. So scream, dialog, prop prop types, we're going to have the get screen function.

So a prop types.funk.is. required. We're gonna have
the scream ID from passed down. So prop types.string.is required. We're going to have the user handle,
we got passed down as well. Prop types.string.is required. And from the state, we're going
to get the screen the object is required. And we can just copy this same thing for the
UI, we need the UI for loading. and here we can do our map state to props to take the
state and return the following. What do we need, we need the screen which will be in
State DOT data dot scream. And we need the UI which is in state the UI. All right, when
we're going to see map, action const map actions to props. For now it's just gonna have get
screens get screen.

I need to export the fault. Connect map state
to props, map actions to props and who have passed with styles. Styles, and the second
will be scream dialog. Alright, so in our component, so this is a dialogue. So we need
a in our state, we need an open Boolean, which is false by default, we the handle open which
sets the state open is true. Let's copy it, paste that change this with close and open
false. All right. Actually, we need to call here when we open the screen we need to call
the get screams because when we caught when we open the screen we need to when we open
the dialog we need to send a request to our server to get our scream so we call the get
scream and we pass it the ID this dot props dot scream ID that we got passed down from
the scream card.

And here inside of we need to create the render render inside of here
let's get so let's do const let's get classes. Let's get the scream. And this will be because
get scream is going to get us the scream and set it in our props as the screen because
we get it from the state here. So here from scream are going to get everything so it's
great scream ID we need the body.

We need the credit Related art, we need the like count.
We need a comment count, even though we're not going to use all of them in this video,
but let's get all of them anyway, we need the user image we need, what else user handle?
And after scream actually, why did I do a scream twice? Like this. And here like this
after scream, we need to get the loading from you Why? So you why. And with the structure
loading from it. And all of this equals this dot props. Let's save. So it formats. And
here after we get all the stuff, we need to return a fragment. Why is it not closing?
Come on, fragment? Oh, what am I doing this is inside the render. So inside the fragment
first thing, of course, is the button that opens this dialog. So my button and the onClick
will be this dot handle open.

And the tip will say expand, scream. And we'll have we'll
have to style it. So let's do tip class name. Let's say classes dot expand button. And Yep,
inside the button, we will have an icon. This will be the unfold more. And with a color
of primary. Actually, I forgot to import this. So here let's copy this and select this old
select this and say on fold more.

So yeah, we have the icon. After we put our dialogue,
so dialogue, lock, close it, we can actually get the stuff from post screen. It's exactly
the same. Actually, even the close button will be the same I think let's copy all of
this. So let's go back here. Let's do this. Yeah, this dot state open handle close for
with max width. And the button close has the onClick contact, close and close button as
the class call. Alright, so here after the button right here, we put our content. So
I say dialogue content. And let's give this a class name of classes dot dialog content. And here because we need to check for loading
or not, let's say dialog, markup. And here after all this stuff, let's say const. Dialogue
markup equals if loading.

Then we're going to use our brought in the the circular progress.
So here, let's say circular progress on this needs to be massive. So sighs let's give 200.
And yeah, this is it. And also, if we're not loading, then we need to show me the grid
container. spacing, let's give a spacing of 16. Why didn't close it, grid. And here we
need items. So grid item. This is the site for the image. So I'm going to give it a width
of five. So SM five. And here we'll put an image source will be user image. And the old
let's say profile. And here let's say let's give it a class name because we need to style
this image profile image. And let's copy this. Actually, it would have been faster if I typed
it but whatever. Actually, maybe not. And here we will. First thing we need to show
is the handle of whoever typed this in whoever posted the screen typography and then here
we'll have a component link because this needs to link to the Users page.

Karla primary,
and here we give a variant similar to the scream card actually exactly the same variant
of H five. And this will go to still backticks slash users slash, dollar sign curly braces,
use a handle. And here, let's close the typography. Actually, no, let's close it like this, because
we need to write stuff inside of it. And here's the art. And then we concatenate the user
handle. I misspelled user handle here like this. Cool. After the typography, we need
to put a horizontal ruler, but I need to click to style this.

So let's call this let's call
this I don't know, invisible separator. And let's go up here in our styles, I think we
might, we might need the global styles. So let's do a steak theme. And then return and
then spread theme here. And this invisible separator will have a border of non because
a horizontal rulers, by default Have some water, I don't want to, I don't want it to
be visible. And let's give it a margin of four. So it creates some space between our
elements. So let's close this tag. And here we get our created art. We put one This one,
this was when this screen was posted. So here, the variant will be body two.

And let's give
this a color. Same like the in the scream card, that color of text secondary. So it's
kind of great to know why these tags are not closing again. So oops, inside of typography,
here, stone expression de j s, and we pass it the created art. And we do dot format.
And I've written this in front of myself in a piece of paper, let me check. So it's H,
colon, dash, a, I mean space a comma, capital M, Double D, quadruple y. So this is the format
of the date. And here we'll have another HR with a class name of classes dot invisible
separator again. And here we'll put the body so say typography. And here, let's have a
variant of body one. That's it. And here, we just put body. All right. This is it for now, let's save. Let's check
if we have any errors. We don't. Cool.

All right, so we get this expand button. And if
we click it, we get nothing. Let's look at our state. Receive truffe one on Boolean attribute
container. That's interesting. And here in our state, look at the data. We're not getting
scream for some reason. Hmm, this dot props dot get screen. Oh, because in the data register,
I forgot to handle the type. Or the Yeah, the type gets set screen. So here, let's say
case, set, scream, scream like this. And here we need to Oh my god, no. Really, come on.
Okay. Sorry about my cups, guys. So state and here we set the scream the singular scream
to simply action dot payload. Let's save. And this time, let's check, we expand. Cool
we get our screen we get all the details of our scream.

And if we look here, in our state,
in our data in the singular scream, we get this scream. So let me change the view to
the tree. So yeah, we get that scream and then if we go to this screen, it will know
here it will change to that screen. All right, so let's style the image. Because right now
it's massive. In the dialogue dialog here in the styles, let me close the terminal.
And here, the profile image, give it a max width of 200 or 200, not 300.

And let's give
it a height. Same 200, I want it to be circular. So let's give it a border radius of 50%. And
us give it object fit of cover in case the ratio doesn't match the one by one so that
it doesn't stretch it. And here as well, I want to style the content. Because right now
all the oldest stuff is kind of going to the edges as well. It's too close to edges, I
want to have some padding, so to push it a bit in.

So let's do dialogue content. And
here, we're just going to give it a padding of 20. Let's save. Let's go here. Let's, let's
make this button go to the right. And now this is container. All right, so our grid
is behaving properly. Now this button is to take to go to the right. So here we say. Close
button. And what do is position? Absolute. And here we say left 90%.

Cool, but some reason
the padding is not working. So what is the padding dialog content? So class name equals
class name, that dialogue content actually with lowercase d? All right, cool. So we're
getting our details inside of the screen. And yeah, looks it looks okay for now. So
here, want to fix some styling. Before we do anything, I want to bring this button to
the right, so it's more visible.

So let's go to scream, scream dialog. And we've actually
given it a class, I believe, where is it? Yeah, expand button. Let's copy this. We've
given it a class, but we didn't style it. So here, let's do expand button. And here,
let's do position. Absolute. Let's give it a left of 90%. Let's
see what it looks like now. we refresh. Cool. It's on the right now. All right, I want to
move this button as well move it a bit down. So it faces the user. And I want to change
the styling. By the way, you can go to Redux. And if you have something that's like going
too fast, for example, the loading stage here, the loading UI, we can go back one level and
just pause there and you can see your animation, or whatever you have, and you can style it.
So this I want to bring it to the middle. And I want it to be a bit less thick than
then what it is right now. So let's go to our code. And here. Where is it? So I'm going
to put it in a diff? Well, we kind of have to so let's do div.

And let's paste it in.
And we're gonna change the thickness. This can take a value for thickness. I'm going
to give it to and here the div will have a class name. And it will be classes dot scollard,
spinner, Dev. And here. Let's do spinner div. Let's give it a text align. of center. So
aligned to the center. Let's give it some margin on the top and bottom. So a margin
top 50 and margin.

Bottom 50. Let's see what it looks like. Here. Alright, we expand. us
go back. Yeah, cool. It's in the middle and it's less thick. It looks much better and
the button is a bit to the left now. Let's actually remove this just Yeah. Alright, so
it looks much better now. Alright, so now what we want to work on is the action buttons.
So this like button here and the common button which does nothing, but it's just an icon,
and the number of comments and likes here as well the same as in the screen. So what
I thought about is that since they're the same, we can go to the screen and this like
button, or we can make it into its own component, because we will need it in the scream dialog
as well.

And one of the good things that you will do one of the best practices is to try
and keep your components as small as possible. And I noticed the screen dialog will be really
massive if we don't divide it into further components. So here in components, let's create
a Like button, button dot j s. And here, we can actually cut this. Oops, bring it in.
Let's do ice top.

Here in the render, we can say return like button. And before that, we
can say const like button, and we need to get authenticated from the state. So we need
the user, we need a couple of things actually here. So we need my button. Because we're
using it from the same level. Actually, it's in the youtell. Go back one level slash utils
slash my button when need link, so import link from react router DOM. We need prop types.
Of course, we need the icons that we have here. So icons, say import, we can actually
just cut to these from here because we don't need them. So paste them here. We need connect
from react Redux. And we need to bring the like and unlike auctions, we don't need the
oops, we don't need them here anymore.

So we can cut this line. We can go down here,
we can remove them from the prop types. And we can remove this map actions to props for
now. And yeah, let's save let's go here. Let's paste it here. And here, we're going to have
prop types sold like button dot prop types. We we need to access the user to user let's
say prop types.object.is required. We need the scream Id actually we were going to pass
it down. So to say prop types dot string that is required. We need the two functions. So
like scream, pro prop types dot funk that is required. We can copy this line and just
add on here. And here we export the fault that's called this Connect map state to props,
map actions to props. connected with this we don't need styles because we have no styles
here can say const. Map state to props equals takes the state and returns we need the user
state user we need to create the map oops map actions to props.

So we'll have the like
scream and the unlike on like scream like this. So here the same actually we need to
cut to these functions as well. So like scream and unlike scream. And here for the here instead
of like button here. We do the component like button and we pass it a scream ID of scream
ID because we've disrupted it from the screen
right here. And here we need to import it for like button from Same level like button.
And here in like button inside the component, we need to paste those functions. And here,
this approach, the user likes everything. And here we check if the like, scream equals
this dot props dot scream ID, because we don't have a scream, we have a scream ID.

And actually,
we need that in the URL, we have that in the prop types already. This is like button with
a lowercase L. Here, we need to say this dot props, dot scream ID. And here the same thing.
And here we need to get authenticated. So const authenticated from this dot props dot
user. And authenticated. And yeah, I think this is for this component, and we save there.
And we save here as well. As check if we have any errors. We don't. Let's check our app,
see if the button is working properly. And it is working the same if we refresh to make
sure that Yep, it's working the same way. If we log out, or click on the like button,
or it doesn't redirect, us check the console. Or this is not working.

Everything looks okay.
Let me check again. Oh, it's actually working. Oh, I see. Because if we click on the side,
that doesn't work, because there's just as big as the icon itself. So what we can do
is we can, we can surround the whole button with the link. So let's put this outside,
let's put the whole button inside of the link. Yeah, and this way it works. Even if we click
on the sides, the whole thing is the link now. Alright, so let's do the same thing inside
of here.

Let's show these two things here. So now that we have it in its own component,
we can just use it like that in the screen dialog. So let's go to scream dialog. Under
the body. So right here, we can see like button and pass a scream ID of scream ID. And we
have it Yeah, we how we got it from the screen. And under that we need to say we need to have
a span. And you will have like count count, like in the scream card. And here we say likes.
And we will have as well the we can copy this actually from screen, this comment button
and the comments icon and the comments text.

So let's save. Actually we need to import
it as well. So here let's say import like button from same level like button. Let's
save see if we have any errors we do. Chat icon is not defined. Sure we don't need this
dialog title. And here let's bring the icon we can copy all this. And here's the Chat
Chat icon. And here say just chat. Space save. We have no errors. Cool. All right, let's
with get the same button Actually, we have to log in because we're logged out.

Alright,
so here if I expand cool, we see the buttons here. And if we click it turns into full Oh,
but the the like count doesn't update here. Let's check our state data. scream. Do we
have any error? The prop uses marked required an auth route, but the values undefined. Okay, this because when we log out, it's okay.
We'll fix this later. All right. So the light count is not changing. I think because the
the screen is not updating.

Yeah, so the scream like count is not updating. We need to update
it. So let's go to data reducer. And right here when we like or unlike the screen, we
need to do a check. So if State DOT screen singular dot scream, ID, so we need to check
when we like a scream, we need to check that scream that's stored in the singular scream
object. If they have the same ID, that means we're like the scream that we have open. So
we need to update the scream, the singular scream with this data that we get back from
the like, or unlike route, which is the scream with the like, count updated. So we do if
it equals action, dot payload, dot scream, ID, then we just do State DOT scream equals
action dot payload.

It should fix it. We open up here, and let's open the state as well
to check. We like cool and we get this updated and the like screamers. Look at the difference.
Yeah, it no here, yeah, incremented the count. And if we unlike it, decrements. So it updates
the data. So this is the current state of our screen dialog, it has only the details
of the screen, I want to add a section where we display the comments that are submitted
to each screen in this dialog.

So let's do that. I'm actually going to create a couple
of folders here to organize our components more otherwise, it's going to be less navigatable.
So let's create a folder called screen. And another one called layout, and another one
called profile. So in the layout, we're going to put the navbar. And then we're going to
put the profile and edit details in the profile folder. And the rest of them will go to the
screen. Alright, so VS code should fix the the relative imports and change the directories.
Actually here and now bar, the post screen would come from we go back one level, and
we go into screen slash post screen. And the rest should be fine. In edit details is changing
automatically. And it's opening up it open in the mob, because it's changing them right
now. And we need to save all files and close this. Let's go to app. And here, we get the
navbar we're going to get it from slash components slash layout slash navbar. And in the home
as well. here where we get the screen, we get it from slash scream slash scream.

And
from profile, we get it from slash profile slash profile. Save. Cool, no more errors.
Let's go to actually let's get rid of this warning. So let's go to home and remove axios.
We don't need it there anymore. Let's save cool, we have no warnings. And our app works
the same way it did earlier. All right. So let's add the comments. And let's go to the
screen dialog. Here. We're going to import a component that we haven't created yet. Let's
do import comments from see this would be in the same directory. So
comments like this. And let's go at the bottom. So here when we are actually not loading,
and we are rendering stuff, let's go here under this grid right here. So here, let's
do comments. And we need to pass it our comments. So let's pass a prop comments with the value
comments. And this comment referred to refers to the actually we haven't extracted it yet
haven't disrupted it.

So let's do that. So it's going to be this comment from inside
the screen. Because if you remember from the API, if we go to Redux go to the state. For
look at data screen, we have an array of comments. And if we don't have any comments, it will
be an empty array. So here we do our comments. And let's save this let's go here in scream
Oh, there's a problem cannot resolve comments because we haven't created that yet.

In scream
let's create comments dot j s. Actually before the comment section I want to add a separator.
So here let's do HR class name is classes. And unlike the one we have already, this is
going to be the visible separator. separator and I want to move the code the styling for
the invisible separator from here to the global theme So let's go to utils theme, unless based
at the bottom, because we're going to need it in comments as well.

And here, let's do
visible separator. And this one is going to have a width of 100%. And as a string, actually,
because this is JavaScript, and it's going to have a border button of one pixel solid,
let's give it a gray. So I'm going to do RGBA 000. So so far, it's just black, and we give
it the opacity of 10%, or 0.1. This is going to be a light gray. So let's give it a margin
bottom of 20 pixels. All right, so this is visible, let me make sure I didn't misspell
anything I didn't call.

Alright, let's go to comments. And here we're going to bring
in these three, so react component, fragment with styles and prop types. Here, we're going
to need some movie stuff. I know already, we're gonna need the grid. So import grid
from material, material UI slash core slash and grid. an import typography from the same
material was slash core slash typography. Alright, let's initialize a styles. Actually,
we need the global theme. So let's take the theme and return this object.

Let's spread
the theme for now. And here, let's do our class. Comments, extends, extends, component.
And, here, let's do our prop types. So comments dot Prop, prop types, here, we're only going
to have the comments that are passed on. So this would be a prop types dot array that
is required. And here, let's do export default. With styles, styles, and comments. All right
here in the component, we're gonna have the render, render. And here, let's extract the
comments to const comments. From the props, this stop props. And, yeah, we need to return
something I saved, but doesn't like it.

Actually, we need the classes as well. So classes here,
let's do return. Here, we're gonna have a grid container, because this is the container.
And inside of this, we're going to have, what are we going to have? We're going to look
through the comments. So let's do comments. dot map. And for each comment, we're gonna
actually, let's do curly braces, because we need to destructure the stuff from inside
comments. And if you remember, comments, me check the singular comment, actually, we don't
have one as a problem, you need to save her.

Anyway, I just want to show you in the state
that the comment the comments will have a four four keys. So body, I just want to remind
you probably know this body created art and use the image and the user handle. So we get
these from comment. So equals comment. And here we do return. So inside we are inside
the grid, the container grid, so let's do a fragment. And since this is a we're looping
through something, because I'm going to learn in react, we need to give it a key and let's
use the created art as a key because it almost never will be not unique.

Okay, so here, let's
say grid. And this will be an item. Let's give it a width of 12. And inside of here,
we're gonna actually nest another grid. So let's say grid container. Because inside of
each comment, we're gonna have a left grid item there where there's a picture, the image
and on the right, there's the details of the comment. So here this is, here we have the
picture. So grid item, as equals, we're gonna have again a width of two inside of it, we're
gonna have the image with the source user image.

The alternative, let's say comment,
we're gonna have, we're gonna give it a class because otherwise, we need to start it otherwise
is going to be massive. So let's give this classes dot comment image. On after this,
we're going to have a grid item. With SM nine, we don't actually have to specify this because
material UI can automatically give it the width nine. But it just looks more readable
in my opinion. So there's let's give this a class name of classes. or comment, data,
and style, this div lighter. And inside of this div, we're first thing is going to have
we're gonna have the, the handle of the user as a link. So typography variant. Let's give
it a head of five similar to the one in the scream card.

So component, B link, do we import
linkwithin Let's import link import link. From react router DOM. Here the component
is linked the two will be so backticks slash users slash dollar sign curly braces user
user handle. All right, we're gonna give it a color of primary. And here, let's close
this. Now actually, here we close it. And inside of the typography, we're gonna have
the handles.

So let's say art or without an art, actually, let's just put the user handle on here are actually in close this done on
what this curly brace I added here for? Hey, we need to show the one the one The comment
was submitted. So typography, the variant of body two with a color of text secondary.
And inside of here, we're going to format the date Actually, let's import ajs. For digests
from DHS, and inside this expression, we're gonna say d, j, s and pass it the created
art dot format. And here, let's format to have this in front of me H, colon. Space a
call corner, quadruple capital M, d, d, and quadruple y. Alright, so under here we're
going to have a separator, so HR with the class name, classes dot invisible is Bo, separator.
Oops, here, we're gonna have the body.

So let's say typography. But the very end variant
of body one. And inside of here, we'll put body and yeah, I think this is it actually has a ruler
between them. So let's do here, let's say HR. Class Name of classes dot visible separator.
Actually visible not invisible. Alright, let's save. Let's save everything. Let's see what
this looks like. So we open up here. Oh, yeah, I forgot to style the image. So let's go here.
So in the styles, that's the most common image. Here let's give it a max width of 100 or 100%.
Near let's give it a height of 100. An object fit in case the ratios are actually one by
one of cover. And let's give it a border radius of 50%. So it's rounded 50 percent. And here
we need to style this div as well. Because I want to give it some margin between an image.
So it's a comment, data. margin, left, margin, chin left, have a say 20 pixels 20. At save.
Look at our depth. So here, cool. If we look at here, we push the rule, actually, we need
to not put the ruler after the last comment.

So what we can do we need to access the index.
So yeah, the map gives us actually access to a second parameter of index, and gives
us where in which index we are. So here, let's take this ruler. And let's put a condition
here, let's say. So you always want the ruler unless we're in the last index. So let's say
index does not equal if index does not equal the last index.

So comments, dot length, minus
one. So if it doesn't equal the last index, then give us the ruler, so render the rule
otherwise, don't render it. So on the last one, it doesn't render it. So yeah, now it
doesn't run the ruler under the last comment. Cool. All right, so we got our comments. So
now that we're showing comments, let's actually show a comment input or comment form right
here that allows us to submit comments as go to scream dialog. And I'm going to create
a component for this. Actually, it's not going to be here, it's going to be under the separator,
sort of a comment form. And we're gonna pass it the scream ID, because we need this one
we're sending one, we're sending a request to that endpoint. By the way, I'm not just
creating a component just for the sake of it, it's better to divide your application
into smaller components.

Because if I were to put the code here on all the functionality
and bring the functions from the Redux actions, it's going to bloat this one component. So
it's good to separate your components. Plus, it helps when debugging, the problem happens,
you will know exactly where it came from. So let's import this. So let's go up here.
So import comment form, from same directory comment form. Alright, let's create this in the scream directory.
Let's say comment, form dot j, s. And here before we write anything, let's actually create
the action, the Redux action. Let's go to Redux actions. Let's actually create a type
for this first. So here, let's say export. const. Submit. Comment. Which equals, actually,
it's not a string here.

What am I doing? Here is submit. fuckin type comment. Alright. I
submit comment. Yeah, didn't misspell anything. Here in data actions. Let's bring it in. Submit,
comment. Let's go under the unlike here, let's say, submit a comment. Here. Let's do export
const. Submit comment. equals, and due to the nature of the endpoint, we need the scream
ID. So let's take the scream ID. And let's take the common data. We need dispatch. So
let's return dispatch. And then do the following. So here, I'm going to say axios dot post.
And the endpoint is slash scream, slash the scream ID. So put a variable here scream,
Id slash comment.

And here we pass the comment, data returns a promise. So then Russ, here
with dispatch, the type that we just created. So type, submit, comment, and the payload,
which the payload which when we submit a comment, we get that comment back. So let's do the
payload is rest or data. We'll show you in a second what we're going to do with the payload.
Here we dispatch clear errors. Since we have the function clear errors here, which by the
way, this is called a an action creator when you create a function that just dispatches
an action. So let's dispatch this action creator and we call it Like this. And actually, let's
look where we have clear errors and replace it with. Let's Let's search for clear errors.
Yeah. So where else actually we have somewhere else where we have, I think, yeah, here, we
can just dispatch clear.

Oops, clear errors, the function. Cool. All right. So let's go
back to our Submit. With dispatch this. Are these are curly braces Not, not square, like
this. And here, we see a catch. And we can actually get validation errors for the comment,
because if it's empty, we get an error for that. So we need to dispatch set error. So
type, set errors, and the payload will be the error dot response dot data. Alright, let's save this. Let's go to the
data reducer and handle this. Submit comment is not exported, or because we didn't save
her. So here let's do or I didn't save, maybe you saved? I don't know.

Submit comment? And
I think it's important. Yep. And here, let's say, what do we do? We need to Okay, let me
do return first. Sometimes it's hard to talk and type at the same time. All right, let's
spread the state. And what we need to do is that, we get this comment back. And since
we have opened this screams dialogue, so this is in this singular scream object, we need
to add this comment that we get back to the comment array in this in the screen.

So if
we look here, just to reiterate, so here, if we open up this, let's say the screen,
let's go to our dev tools, we go to our state. So inside data screen, we have this array
of comments, what we need to do, we need to get that comment and put it at the top. So
if we were to put a comment here, it will be at the top here, because it's the newest
one. And here so what we need to do is we spread the state and we say, scream, which
and then we spread our existing screen. So status screen. And here we say comments. And
inside of comments. We say action dot payload, which is the comment that we just submitted.
And then we spread the rest of the comments. So spread State DOT scream dot comments. All
right, let's save. Now let's go to our comment form. Hey, we need a couple of things. Let's
get the these three. A safe first ice tub, remove this export here, and then paste here.
Here, we're going to need some movie stuff as well.

So movie stuff, let's get, we're
going to need the button, the submit button of the form. So from material UI slash core
slash button. Let's copy this two more times, we're going to need the grid because we're
already remember we're already integrated because of the screen dialog. And here we're
going to need the text field. Alright, let's do a styles const styles equals theme. And
then returns we're going to need the textfield styling. So to spread the theme. I don't think
we have any styling for this component. So let's leave it like that. Here we have a state.
Since we have a form, we'll have the body of the comment as empty initially. And here
let's do actually we need to bring in Redux. So or like Connect Redux stuff, say import
can connect. Now guys, you don't have to do these comments. But if you expand your functionality
more and you bring in more stuff, it's cool to comment on your on your code or on your
import.

It makes it easier to navigate. So we get Connect as per usual from react Redux.
And we need this action that we just create soldiers to import. Submit comment. From go
back one level go back another level Redux slash actions slash data actions. Alright,
so here Yeah, we got prop types who can do prop types. But before that, let's let's cut
this and let's say export default, connect map state to props. Since we have one action,
we can just But her submit comment. And the second one will be with styles, styles.

And
we pass our component. So here let's do const. Map state to props equals state and returns
the following. And here we need to access the both the UI and case we get errors. So
UI is state.ui. And we need, we need authenticated from user. Because we don't want to show this
form for not authenticated. So let's say authenticated from State DOT user dot authenticated. Alright,
let's do the prop types. So comment on dot prop types. We have our function. So submit
comment is prop types dot bank that is required. We have our props from the state which is
which our UI prop. Prop. Okay, let me try again. prototypes that
object that is required. And we can just copy this. Here we see what do we have? We have
the classes from, from with styles, and we have the scream ID that we got passed down.
This is a string and we have the authenticated, then dedicated. And this is a Boolean, so
disable. I think this is it for our props. Yeah. Okay. Let's go to the render, let's
say const.

Let's get our classes and authenticated from this dot props. And here we say let's
say return. Comment, form markup. And here, let's say const. comment, comment, form
markup equals, and we do a ternary. operator. So if authenticated, if we are authenticated,
we return something else we actually return No, because we don't want to see this if we're
not authenticated. So here let's, what do we return we return a grid item because we're
already in a container, because of house in screen dialog right here.

Where are we? Yeah,
we're here. So we're already in a container yet. So we just put a grid item s equals 12. Here, let's give it an inline style.
And let's give it a text align. Center. I want the button to align in the middle. Here,
let's do a form on submit equals this dot handle, submit. And he will put up whoops,
we'll put our text field text field, we're going to have a name. It's
going to be body. Whatever we'll we'll have a type of text.
We have let's put a label, of course that says comment. On scream. Spread a place hole
actually has not put a placeholder.

It's kind of self explanatory. So let's put an error
of errors dot whoops, Oh, actually, this reminds me that we didn't put errors. So errors comment,
this is what we get back from our endpoint. We have an validation error with the comment.
So if it if we have a comment, or a comment, we set this to true, else we set it to false.
And let's put errors in the state errors. And let's actually get errors from the state.
So const errors equals this dot State DOT errors. So here we have a helper text in case
we get an error, and this will be arrows.rs comment, sick of saying errors, twisting my
tongue too much value equals this dot State DOT body.

An on change is this dot handle
change. And let's give it forward. Because otherwise it's just gonna take off Let's give
it actually the our class. So class name, the global styling, so class classes, classes,
that text field. I think this is it. Yeah, let's close this tag. And let's have a button
of type Submit. variant contained, because that's the style we've been going with color
primary and the class name, the global class name classes dot button to give it the margin.
Let's close this. And this will say Submit. And I think this is it. Actually, no, let's
put a ruler under here.

So let's say, hey, char, the class name. Classes dot, visible,
separate. Alright, let's close this tag. And no, not like this, like this. And, here, let's
create our form. For methods. So let's say on change takes an event. And here we do this
dot set state. Oops, we said the state and the name will be event dot target dot name.
We only have one input, but this is this works for all forms. So event, we bind it to event
dot target dot value. All right, let's create the onsubmit not on change, handle change.
I'm doing this handle thing because in the movie document documentation, they do that.
So to be less confusing, I just follow the the convention because I'm using that framework.
But you don't have to.

So handle submit takes the event. And here we do event dot prevent.
Default. And here we call our our action this dot props. dot submit comment. comment, comment.
And we passed this paper Oh yeah, the scream ID. So this dot props we've passed, we've
been passed this already. So scream ID and the second will be an object with a key body,
not Cody body. And the value of this will be this dot State DOT body.

And we need to
get the errors as well. In case there is any so let's say component. component will receive
props. Next props. Here we need to check for them if next props.ui to get you why. Yeah,
we did. If next props.ui dot errors, then this dot set state errors. Next props.ui.ui
dot errors. calls. I think this is it. Yeah, this is let's test this out. Let's save errors
is not defined. Oh, to initialize it as an empty object here.
Yeah, fragment is defined but never used. Actually, we don't need fragment, because
we're returning one element anyway. Cool. Let's check our up. So we open up. There's no form. Oh, we're not logged in?
Of course.

So use that we're not logged in. Maybe you're logged in. So use that. At email, comm one through six
login. I open up this, we get a comment section here. Cool. I write a comment Hello, mate.
I send it call it persist and it shows up instantly. But it doesn't clear the form that's
handled up. So huh? here when we receive props, or we can check
because once we send this, we can check. Once we get props, we can check that we don't have
errors. So actually not here. So exclamation mark. Not errors. I mean not next props.ui
dot errors. And the same thing we did in the ad scream guys. So our next Next props.ui
dot loading, or just not here as well. And what we need to do here, if this is the case,
this dot set state body is empty.

All right, let's try again. I say hello again, bro. We
send this cool and it resets it. If I send empty, we get errors cool. If I submit, actually,
oh, we're not clearing the earth. So I know now, I'm going to submit it's going to show
me an error instantly. Yep, we need to clear the errors as well. From here. What we need
to do is that we need to clear errors once we close this dialog.

So we will do this from
the scream dialog. So here, actually, we need to import the clear errors first. So here,
let's say clear errors. And where are we so here, in handle close, we
need to set the state open to false. And we need to call the clear arrows this dot props
dot clear. Earth, call it like this. We need to add it to our prop types. Up here, so clear
errors is a prop types.funk.is required. Comma, let's save. Let's go here. So if we get an
error, and we go again, and oh, the stop prosecutors' not function is or not clear errors. Call
it here. Oh, of course forgot to add it to the map actions to props. Clear errors like
this save this time it should work. So if there is any error, let's let's double check
as well in the state.

So tree UI, there's no error right? Now. Let me put them like
this. So actually, no, I don't need to type anything. If I have an empty we have an error.
And if I close it, it dispatches clear errors and it clears the errors cool. So let's actually
create the user page. So when we click right now on a user handle, it just takes us to
slash user slash that user handle and there's nothing.

So let's actually create this page.
Alright, let's go to pages, and let's create here, a user dot j s, lowercase, it doesn't
really matter. I've got questions on this, why use components and pages, it's just a
convention, you know, there's multiple conventions on how to do things, just pick yours and stick
with it. Alright, let's go to app.

And actually, let me close the terminal. Let's set up a
route here. So here, I'm gonna import it first. So import user. From same level, but pages
slash user. Let me put a space between those. And here, let's put a route. So route, exact
path equals, and this will be slash users slash colon handle. Handle not handle. Sorry,
for the typos, guys. So component equals user. Now, before we create the sound or create
the action, so let's go to data actions. And we're going to create export const, I'm going
to call it get user data. But don't confuse it with the other get user data from the user
actions. And this will take a user handle and it will go through dispatch. And here
first would dispatch a loading type. So dispatch type, loading data. And here we say axios
dot get backticks slash user singular.

That's how we set up our back end route. Don't confuse
the two. So dollar sign curly braces use a handle that we have passed to this function.
And here we do, then, then result. Guys, if you remember, if you don't remember,
I'll remind you so this is the type of data we get from requesting from slash user slash
handle. So we get a user object and the screens object. So what we want to do now is we want
to set the screens to our state screams. So here we do dispatch. The type will We'll be
set screams and we're not going to set the so payload will be action, not not action
sorry, rez dot data dot screens. And we're not going to set the user details to this
because the user details is always the authenticated user.

Here, we say the catch, we don't need
to stop loading because set errors that set screams does that. And here let's do catch
errors. And here we just dispatch the same type set screams with the payload of No. Alright,
so yeah, no, no semicolon, here, we save. Actually, we don't need or here, we could
just like keep it like that. Save here. And let's actually create this user component,
or page. So RC e tub, let's get rid of this export. And here, we're going to need the
prop types. Let's import axios. And I'll show you why
we need axios in a second. Let's import scream. Components slash scream, slash scream, Pascoe
cased here. Let's import the grid from material UI. And we need, we need to connect. And we
need this function that we just created. So get us a data from Redux actions, data actions. Let's set up
our prototypes. So let's actually set up the map the map state to props first. So const,
map state to props is going to take the state and return the following. So we just need
the data.

So So data, state that data. And here let's just do connect map state to props.
We only need one action. So we can put it in a object like this. So get user data. And
we wrap the component in the parentheses and here, let's say user, the prop types equals
the function get user data, which is a prop types.funk.is required. And the data which
is an object. So prop types.object.is, required. So here, let's, when we load the component,
so let's do component did mount.

And here when we load the component, we want to fetch
the user, this user's details, so let's get the handle from the URL. So we can do that
by doing the columns handle, let's put it in a variable. So this dot props dot match,
which holds the details about the URL, the path, name, base URL, all this stuff, the
parents, which are the parameters, and we have access to only one parameter, which is
the handle, because that's how we set up the route if you remember, so we have this one
parameter handle, now we get it, we put it in this variable.

And we can do this dot props,
dot get user data and pass the handle. And we also now need to get the user details.
So let's do axio. So I want to send another request to see got axios slash users slash
user rather singular, the same request that we send from our action. So here we pass the
handle, oops handle. Get then rather. And then here, actually, we need the profile and
the state. So let's do state equals. Here we have a profile property. Survey no for
now. And here when we get the result we do this dot set state. We said the profile to
res dot data The user and we forget an error, we just console log it. Now I know we can
as well create another, another entry in our data in the state and put this data in there.
But this is going to be a static profile, it's not nothing's going to change about it.
So we don't need to store it in our global state.

So we can just fetch it and have it
here inside the component. So here in the render, skirt, the screams, and the loading
from the data. So we destructure these from this dot props dot data. And here where we
return stuff, we're going to have something similar to the homepage. So can we actually
copy it from the homepage? Yeah. Let's copy this. Let's go back to user space. This here,
we already brought in grid right here. And here, we say, screams. markup. And here instead
of profile, I'm going to put a thing called static profile component called static profile,
which we haven't created.

But we will in a moment on let's pass it a profile, this dot
State DOT profile. And here, let's create the screen mock up. So const, screen mock
screams mock up equals. And of course, let's check for loading. If we are loading then
show a paragraph saying loading data. Else. Here we do. What do we do? Actually, we do
another check here. So let's do else if screams, because there could we could go to a user's
page, and they could have no screams, maybe they haven't posted then yet. So if screams
equals No, then we set we set the content to be a paragraph that says, No screams from
this user. Now you can style this more. It's up to you. I'm just gonna leave it like this
for now.

If we do have any screams, accused, excuse me. We do screams dot map. And then
for each scream, we're going to return a scream with the key scream dot scream ID similar
to the homepage. And we passed the scream. scream. We close the tag. So I think we're
done here. Yeah, let's create the static profile. Let's import it from so right here, say import
static profile from go back on level components slash profile slash static profile. Let's
create this here. Static profile address. Here let's import react and fragment from
react. And maybe let's copy some stuff from here.

Or
maybe from here prop types. I wanted to get with styles, sexually typed out styles from
material UI slash courses slash styles slash with styles. We're going to need a j s. From
data they j s. And here let's do import link from material UI. Slash link. Here we need
paper. trail uY slash course slash paper. Copy this but it's never too late control
the typography, typography. And let's get some icons. Here we say the movie Still, we
need the calendar today.

So similar to profile so we can get those three icons from here.
So calendar location and the link icon. So these three spaced them here. We're going
to use styles similar as well to the user profile style. So let's go copy these. Let's
go back to static profile, let's paste. And here, I'm going to remove the button because
we're not going to have edit buttons, because this is not our profile.

This is static profile.
So we removed that button. So here we remove as well, the buttons, and the so the buttons
from here and we removed this SVG button thing from here. Let's save. And here this, this
component is going to be a functional component. So let's say static profile. Equals takes
a props. And let's export it. So export default with styles, styles. And what is this static profile? Let's do our prop types. We have profile which
have been passed down. So this will be prop types.object.is. required. And we have classes
from with classes with styles rather, prop types.object.is required.

Alright, so here,
we need to destructure a couple of things. So let's say const classes. And we have profile.
So we need some stuff from there. So profile colon, and we do curly braces. And we get
what do we get, get handle created art. Okay, image URL, and the bio, website and location.
And this equals this dot props, actually just props because this is a functional component.
So here we do return. And here, let's wrap everything in a paper. Actually, I think I
could copy everything from profile and edit it. So it's good to profile, copy this whole
paper tag. And let's come here, paste it. So we're gonna need, so we're gonna need the
image, we don't need the input and the button here. So let's delete this. We're gonna need
the link the same way I did I call it mu link. Let's call it more link from link. And we
need the link from react router Dom actually. So let's do import link. The structure is
structured from react router, Dom.

So we need that we need the link, we show the buyer the
location, the website. And here we don't have the edited details of the button to log out.
So I think this should work. So let's save everything. And let's look if we have any
errors. We don't. Cool. let's reload the entire thing. And let's go to a profile. cannot read
property No. Handle have no. So the profile we got passed down is no I think profile check
on the user.

This that stayed that. Oh, of course. Here we actually check if we have
a profile because it could be loading or we don't have any profile. So let's cut this
and let's do an expression here. Let's say this dot State DOT profile and the equals
No. So for equals No Then let's return a paragraph saying loading profile.dot.we do hear colons.
So else we show Yeah, we show this we paste what we had there. So let's save. Let's go
back cool. And we get the profile of Jane last. And her screams which are just one could
go back to home click on Johnny we get his profile and his scream. And this is the normal
screen so we can still interact with it the same way we do in the home.

So cool. Like
we have now the user page and we can go to it and everything works just fine. What I want to do right now is we need before
we implement notifications, we need to set up a way where when we type a URL for a screen
we straight away Go to the screen because otherwise when we click on a notification,
we can't do anything.

So what we need to do we need to set up a way in which when we let's
say you want to go to user slash Johnny slash scream, slash scream ID of whatever his scream
when we click And to hear, we need to go straight away to that screen. One thing I want to fix
first, when we are actually logged out, there's a an error, or a warning that says the proper
user in auth route is not required. Let's fix that. So let's go to our auth route right
here. And here, let's make it not required, because sometimes we won't have a user if
we're not logged in. And that's okay, this is still gonna work. So remove is required,
let's save and the error should be gone. And I'm going to be checking if we have any other
one warnings and fix them.

Alright, let's go to App let's set up a route for for what
we're trying to do. Let me close the terminal. So here, I'm going to add another route. So
route, exact path equals, and this will be slash users slash colon handle, slash scream,
slash colon scream, ID. And this will go to the component, the same component user, but
with a trick and you will see, let's save here, let's go to user or as user right here.
Now here in user, we need to check if we have this parameter in our URL, or in our path.
So here in component did mount I go here, actually, I say const.

Scream, ID equals this
dot props dot match, dot params, dot scream, ID. Now of course, we could maybe just be
on the user's page, so we don't have this, which is fine, it's going to be undefined.
So here, we do if scream, ID. So if we have it, then this dot set state, let's call it
scream, Id Param. and set it to scream ID that we just got. So if we have it, we set
it in the state, sexually initialized here, this variable and give it a valid value of
null initially. So we can come down here in the in the render right here.

Let's extract
it. So const. What is that scream? Id Param equals this dot state. So of course, if we
don't have it, it's going to be no, which is fine. And right here, we don't actually
just run through the screens, we do another check. So if we actually have screens, then
here we do another check. And we say, if not scream, Id Param. So if it's not, then yeah,
show the screens like this. That's fine. Now, another. So actually, yeah, actually, here,
I need to put a question mark, because this is another ternary, we're chaining another
ternary operator. So if not scream ID parents then don't do anything else. So if we have
the scream ID params. So we're trying to visit a screen, then let's do this. Now what we
need to do here, we need to find the screen that has this scream ID and pass it a property
of open dialog so that we will know which screen to open once the page loads. So here
I'm going to do if scream dot m.

Actually, no, I need to do the map first. So let's do
screams, screams dot map. And here I say scream. Inside curly braces in here, we do our Chuck's
of F scream, dot scream ID does not equal scream, Id Param then it's not this scream
that we want to open. So we just return like this. So I can just copy this the same way
we return them here. Now here, else return. Now this is when we actually find that one
scream that has the script, same scream ideas that one we're trying to open. So here we
just pass a pass a prop open dialogue. And if we just pass it like this is just going
to pass the property open dialogue with the value of true. Okay, so now let's go to screen.
Now this is kind of this is prop drilling, but it's okay, we're drilling only one property,
not massive objects and a lot of updates and stuff like this.

So how would we go actually
here? No, actually, we need to pass it to the screen
dialog. So here in the screen dialogue, let's say open dialogue equals this dot props because
we passed it down, dot open dialogue. And so if we don't have, it's not, it's gonna
pass a, an undefined value. So that's okay. And here let's add it to the prop types. So
we say open dialogue is a prop types dot For bullying, and it's not required because most
of them will not have this property.

And some, sometimes none of them will have it. So let's
go to the open dialog and handle this logic. Now, here, we're going to add a component
did mount. So let's go here under the state, let's say component. There did mount. And
here, what we need to do is we just need to check if we have the open dialog. So which
if you do this dot props, if this dot props dot open dialog, then we just call this dot
handle open. Let's save all files. And let's check our application. So let's open the Redux
state. So let's look for example, this one. This one right here. So now we have this one
in our screen. Let's take the idea of it. So this is by Johnny, and we have the idea
of it. So did Oh, no, actually, I typed that. Earlier, I got confused for a second. Okay,
let's refresh the homepage, just in case. And now if I type slash users slash Johnny,
slash, scream, slash that ID, it should take us to that user's page and open the screen,
which it does cool.

And, and so now what I want to do is I want to do something like
Twitter. So here on Twitter, as you see, if I open this scream, I mean, the scream this
tweet, if I open this tweet, it's going to change the URL to that slash that user slash
status slash the ID of this tweet. And if I close it, it goes back to the original one.
And if I open this, and I actually just go to this URL, so I type enter, who go to that
user's page and open it. And if I click away, it just goes back to that user's page. So
let's actually implement the same behavior for our application. So let's go to Let's
close Twitter. Let's go to our app. So here in the handle open, we're gonna have some
logic. So this happens after we open the, the screen. So here, let's make some space.
Oops, make some space like this. Let's say we're gonna have two variables here. Let's
call this one old path. And the old path will be the path that we have currently.

So window,
dot location, dot path name. And here, I'm gonna get two things const. Use a handle,
handle. And the scream ID remember, we've been passed these down from scream, so equals
this dot props. And here, we're going to form the path that is supposed to be the path for
this scream. So we'll be we'll call it new path. So this should always be the path for
this scream that we've just opened. So backticks, slash users slash, and put the user handle
and then slash scream, slash, and then put the scream ID. Now here, we can just do window,
dot, push, push state.

And here, we don't need to pass any data. So you can say no,
no. And then for the URL, we just passed the new path. Let's save and let's see, look at
our app. So now if I open this, it should change the URL to slash users slash user slash
scream slash the ID of this one. Okay, so push date is not a function. Oh, window dot
history. dot push date. Sorry about that. So let's refresh. We open this cool, and we
get this URL. Nice. Oh, but it's actually not, we wanted to actually change back. So
let's add that logic as well. So here, we need to as well reverted the change
from handle close. So we need to store them in the state. So you can access them from
both functions. So or methods rather. So here when I said the state, we need to set as well
values for the old path and the new path, we need to put them here. So old path. Ups
path is an empty string and new path. This is well an empty string.

So here when we close
the dialog, we want to do a window dot history, which does nothing By the way, it just changed.
Is the URL at the top. But of course, it benefits the the application so that we will know where
to go. And you will know where we are by just checking the URL from different components.
So this dot, State DOT old path. So now when we go, when we close it, it should revert
back to the old path. So let's save and let's test that. Let's refresh. Let's open this.
Cool, it takes us back to the old path. And even from the Users page, if we do this, and
we go back, it gives us the old path.

So it doesn't just give us slash, it actually saves
the path that we had. And then when we close, it takes us back. Okay, there's an edge case
for this, which is, when we just take a URL, let me go to another user because slash user
slash user is a bit confusing. So when I take this screen, and I just press enter, right
now, there is no old URL. So if I click away, it's not going to work because the old URL
is the same as the new one. So let's actually handle this edge case. So here, under here,
I'm going to say if old path equals new path, then what we need to do is we need to say
old path equals slash users, users slash user handle like this.

Because when we come from
another from another, from completely a different place, and we click away, we should just go
back to the Users page, like exactly like on Twitter, and it works right now. So if
I click on this, and I just click enter here, and I click away, it will go back to the Users
page. Cool. Okay, so let's create the notifications.

Now. Let's go to here in navbar. And here,
instead of notifications in this button, let's just leave this notifications tag, but it's
not going to actually be the icon is going to be a new component that we're going to
create. Let's put it in the same folder. So let's say import notifications from same directory
notifications. And let's create this file. So notifications, dot j, s, and here, we're
going to have some similar imports to screen. So I'm going to take the first six right here.
Let's go back to notifications, paste them, the only one we don't need is the width styles.
And for this, we're going to use the menu component.

So if we go to material UI component
demos, and where is it right here menu, we're just going to use the simple menu. So if you
if you expand the code, it has something called anchor element, and you can change the anchor
and you will anchor around a different one. So for example, if What if it were to anchor
around my account, when you click it, my account appears in the middle. But for our case, I'm
just gonna let it always anchor at the top, so we just see as a normal drop down. Alright,
so here, I'm going to bring in some movie stuff. So let's say movie stuff. And here
we'll say first is the menu is the menu, excuse me. Slash material UI, slash core slash menu. And here, I'm just gonna
copy this line and paste it five more times.

So let's click here Ctrl. D, we need menu
item. We need icon button. We need tooltip. Type, hug, typography, and batch, show you
what these things do. We need a couple of icons. So here let's say import notifications
icon from material, UI slash icon slash notifications.
And we can copy this on here, let's say favorite, favorite. And here we'll say chat. Select
this control the chat. Here, let's bringing the Redux stuff. Import connect from react
Redux. Here, let's import an action that we haven't created yet.

Let's call this mark
notifications, notification notifications. Read, which is going to be executed once we
expand our notifications. So just like on Facebook, or I think even on Twitter, when
you expand your notification They're automatically marked red. So from go back to levels Redux
slash actions slash user actions. And here let's do our class notifications extends,
component. And we will have a state will have an anchor element of no initially, let's export
here, export, connect, map state, to props. And here, guys, if you remember, we already
have our notifications, we got the state, we go to user, or actually, we're not logged
in, let me log in quickly.

So okay, so if you look here, we already have a couple of
notifications. So we just need to show them. Alright, let's go to our notifications here
map state to props. And we only need one action. And we can put it in the subject is Mark notifications
read. And we connected to notifications. Here is export default, let's say notifications
dot prop types. And we have only two so the function mark, notifications read is a prop
types dot func is required. And the notifications is as well a prop, whoops, prop types.object.is
required. And here let's do const map state to props will take the state and return the
following. And here we need notifications from State DOT user dot notifications. Alright,
let's actually create this action first, because that makes more sense. Let's go to user actions.
And here at the bottom, I'm gonna say export default. Actually, let me create the type
first. So it imports it. Here under the user types, I'm gonna say export const. Mark, notifications,
read. I'm just gonna copy this so that I don't make a typo because I always do that.

So equals
the string. So let's go back to user actions here, let's say the not default, export const,
Mark, notifications read. And here it will take. Let's call it data for now. Or let's
call them notifications. Actually, they're an array of IDs. So let's say notification
IDs. And it's going to take this patch. And here, we just need to send an axios request.
So post to slash notifications. And we pass the what is it notifications IDs. And here
that then if we get a result, we dispatch a type of Mark notifications rather than an
import system. It's important, we don't need actually a payload. So here we say the catch
error. We're just console dot log.

So Alright, let's go to our user reducer and
handle this type or this type. So here, I'm say case mark, notifications read. And make
sure if it doesn't import it for you, you import it yourself. And here, what we need
to do is when we mark some notifications read if we go to our state here, so let's go to
user notifications. If we mark them read, we just need oops, we just need to loop through
them and change this red property from false to true. So we have access to them right now,
by just doing State DOT notifications.

And what we need to do we need to do for each,
we loop through them. For each not I'm going to call it for notifications. We will say
not dot read, not read equals true. All right. So here we just we need to return the state
of course, returns spread the state. Okay, so this is this is fine. For now let's go
back to notifications.

And here in the render We need to take the notifications from the
props const notification notifications equals this dot props dot notifications. Here, we
need to do the anchor element equals this dot State DOT anchor element. And notice I'm
not using the structure in here because sometimes it makes less sense to use D structuring when
you have one thing. Okay, so let's say let notification notification icon. Now, depending
on the type of notification, we're going to have a different icon. So if it's a notification
on a comment, we're going to have the chat icon. If it's a notification on a like, we're
going to have the favorite icon. So here, we need to check if we have any notifications
in the first place. So if notifications, and if we have notifications, we need to check
that notifications. The length is bigger than bigger than zero. So if this is the case,
we need to, what we need to do is we need to have two types of notifications.

If it's
red, we're going to give it a color of secondary, otherwise, we're going to give it like a normal
color. So here we will say, so here we check. If we have any unread notifications, then
we need to show a, so we broke our thing. So we need to show a badge on the icon of
the notification with the number of the unread notifications. Otherwise, we just show the
icon without any badge. So here, we can check by doing notifications dot filter.

And here
we filter for not where not the red equals false. So this will, by filter filter in like
this, this will have a result of only the notifications that have a read of false. I
mean, if the array that has some notifications that have a read property of false is has
a length of bigger than zero, that means there are certain notifications that are unread.
So here if this is the case, so we use it as a condition, and we do a ternary.

So if
this is the case, that means we have unread notifications. So let's open this. And let's
say notifications, notifications icon equals the following. So here we say badge, we're
surrounded with badge. That's how badge works. And when we say badge, content equals and
here, we need to actually give it a number. So how many notifications are unread, which
is this array right here. So actually, I forgot to change change dot length. So actually,
this is the number of the notifications that are unread. So this is the content of the
of the badge. And here we need to add a color of secondary so it stands out and we can see
it. And here let's close this badge and inside the badge, we put the icon so notification
icon, which is just the notification icon. And here, so outside of here between these
two parentheses, we do a colon so else, we just do notifications. icon equals just the
regular notifications icon. Actually, this is a lower case, because it's it's this this
thing right here. Actually, it's this. I mean, make sure I have
the right variable here.

So notifications icon is this one. Cool. Okay, I have a problem
with my parenthesis. I think these are extra. Okay, yeah. So this is fine. Now, we need
to handle the else case. So else we can we'll we'll do the same here. So notification icon
equals notification icon, because we could have notifications and all of them are read.
In that case, we do this and we have no notifications. And in that case, as well as this, we just
put the icon. Alright, so here we are actually just to return. Inside, we're gonna wrap everything
in a div. Or actually, let's bring in a fragment That's better. So avoid the div soup. So let's
replace this div with fragment. And here, I'm gonna start of course with the button
that triggers all of this. And here to say we're surrounded with a tool tip with a placement,
not placeholder place meant of top and this will Have a title and you will say, just notifications.
And inside of here, we're going to have an icon button. With an area area owns, oops,
area owns you have if anchor element, then we'll just do a simple menu.

This is from
the documentation. Oops, else is undefined. Here, which I don't know, I honestly don't
know what these do, but they're from the documentation. So I'm just going to put them these two properties
has pop up, construe, and it's gonna have an onClick. This dot handle open. And inside
the icon button, we're gonna put our notifications icon, so notifications icon. All right, so
under this tooltip, we're gonna have our menu, some menu menu like this, here will give us
an idea of simple menu in case. Actually, we don't need the ID, I didn't even type it
correctly. So anchor element will be the anchor element with that we just that we disrupted
the structured earlier, the open will be let's change the Boolean on anchor elements. So
if we have one is going to be true else it's going to be false. So the unclose will be
this dot handle close. And we'll give it an on entered. Now this all entered is triggered
once the menu is opened. And this is what we're going to use to actually send a request
to our back end and mark these notifications red.

And we'll call this on menu opened as
close this and inside of here, we're going to have something called notifications markup.
And this is of course, it's going to depend on a couple of things. So here, let's create
our notifications markup. So I'm gonna say let notifications, markup equals. And here
I'm gonna say if notifications. And notifications, oops, notifications, the length is bigger
than zero. So here what we need to do, we're going to map through the notifications and
show each one. So here we say notifications dot mob, I'm sorry about the
typos guys, like it's the end of the day, and I'm kind of like tired to be honest. And
this is going to be the last video I'm recording, otherwise, I'm just not going to be that productive.
Alright, so inside of this notification, we're gonna have a couple of things because, like,
let me just show you depends on the on the notification, we're gonna have a different
string that we put inside of the notification.

So, for example, if the type is comment, we'll
say commented on if the type of like will say liked your excetera. And you'll see what
in a second. So say const verb, I'm going to call it equals. Now depending on the notification
that type, so I just called it not by the way, in this map, so not dot type, in equals,
like, then we will call the verb liked. Else, we have two types. So else is probably it's
definitely a comment.

So we say commented on. And here, we need to also have the time
when this happened. And for this we're going to use the dangers from now. And actually,
we need to extend digest so inside the render, let's say they, they j s dot extend, and we
pass it the relative time plugin to actually important Yes, pass it the relative time.
And inside of here we'll say time equals day j s, and we pass it not dot created art dot
from now. Now we need the icon color. Because if it's unread, it's going to be red. If it's
red, it's going to be like normal. So here we say If not the red, then it's going to
be primary. Else it's going to be secondary.

And we also need the icon, the, the icon depends
on the on the type of the notification. So here we close, not dot type, equals like.
So if it equals like, then open parentheses, and let's say favorite icon. So if it's a
like, it's going to be a hot icon, and the color will be icon, color.

Color. And the
What do we have, we have, let's give it a style, style of margin. Actually, we need
two curly braces here margin, right? Of 10. Doing in lifestyle for this one guys, you
can, I don't want to add with styles just to have this style. And here, if not, it's
going to be a chat icon, because it's going to be a comment notification with a color
of icon color. And with the same style, and we close the the icon like this. Actually,
before we carry on, let's handle the else so that it doesn't show any like squiggly
lines here. So elsewhere notifications, we show and menu item with an onClick. That just
closes this. So on click of handle, close. And it's going to say you have no notifications
yet. So here, let's carry on. So now after we have all these variables, we can return
what we want to return.

So let's return the following. And here it's going to be a menu
item. With the we have we need the key because we're iterating through an array with the
key would be the created art. And we need an onClick. And this will be this dot handle
close as well. And inside the menu, we're going to have the icon The first thing, and
after that we'll have a typography of component link, because this is going to be a link to
the screen and the color of the fault. And the variant of body one, and it's gonna have
a to property because it's a link to slash users slash and we put the notification dot
recipient like this, slash scream slash notification dot scream, ID, I will close this typography
and here it's gonna say not dot sender.

So the the, the handle of this person, space verb, so whether liked or commented on. And then
we say your scream, spray, and then here we put the time at the same time like this. And
this will say like five minutes ago or whatever. So let's go up here and create our functions
our handle open and handle close and all that shit outside the render. So here's the handle
open equals, it's gonna take an event. I'm just gonna do this dot set state unka element
is event dot target, which is always going to be the icon here to say handle close equals
doesn't take anything. And it just sets the state on element to Nola gun, so closes the
thing the menus. And here let's say on menu opened, this is what sends a request to our
back end to to mark the notifications read. And if you remember properly, like the back
end, we need to send an array of the notification the IDs of the notifications that we want
to mark read.

So we can do this by a say LED on red. Let's call it unread notifications,
IDs equals IDs equals this dot props dot notifications dot map. And what we're going to need to do
here not, we need to map through the notifications that have a not read or false or not, not
read. And actually know here we filter will filter them, not map them. So we only have
the ones that are not read. Now we chain a map. And what we need to do we map the notification
to not.we have a key, a key notification, ID. So this will return us an array of the
IDs of the ones that have red false. And what we need to do with this array, we just need
to call this dot props dot Mark notifications red, and we just passed this unread notifications
ID and that should take care of it. So this should work. Let's look at our console. And
we have notifications icon not defined line 53. Or is it because it's notifications icon.
Oh, cool, no more Earth.

Alright, let's look it up and cool. We get three unread notifications.
And if we open our state, let's, let's put this like like this, we open the state, we
go here, we look at our user, we go look at our notifications, and they have a read of
false. And if we click here, so now there are already because they're all unread. And
if we click on this action, or click on difference, we see that it changed in the notification
and it changed all the reds, all the red properties from false to true.

Cool. And if we click
away, there's no more badge anymore. And if we click we see that there are blue because
they are red. And if we click on this one, it takes us to this to this scream ID cool.
So right now in our application, if we load if we reload or load our up, we'll see quickly
these loading texts show instead of the profile and the screens while they are actually loading.
So let's change this into something more visually appealing. The technique that I really like
is called a loading skeleton YouTube user set. So if I reload YouTube, you'll see these
boxes, these placeholder divs, while the videos actually load, and the thumbnails and everything,
let's actually implement this in our application. Oh, by the way, one thing that I changed I
fixed from last video, the notifications in the prop types in the notifications component
is a prop types dot array and not prop data object because there's multiple ones.

So make
sure you fix that. So let's go to home. And here in the home while we're loading the screams,
we don't say loading, we say, scream, skeleton, which we will create in
a second. Let's copy that unless go here, say import screen skeleton from go back one
level. And we were going to put this in the util so utils slash screen skeleton. And let's
copy this whole import or let's go to the user page. And here paste it. And let's go
down here. While we load the data, we just put the scream skeleton is that alright, let's
create this component. So when you tell I'm going to say scream, scream skeleton.js I
here we're going to need react for react and fragment, because we're gonna have multiple
ones. So we need to wrap them in a fragment.

So here we're going to bring these from react,
we're going to need the no image because we want to show this no image while the images
are loading, because we don't have the actual user image. And by the way, I'll put this
link in the description so you can download it. So I'm just going to download it now download
the 640 by 641. And we can actually just grab a drag and drop it into the image folder.
I'm going to call this no dash image. And it's dot png. So let's import that. So import,
no image from and by the way this you can name anything, it's just an identifier. So
it's going to be from going back one level slash images slash no dash image or whatever
you named it. dot png. Let's bring prop types. on here it's good to see Mui here we need
three things the card is going to be just like the actual card but with no content material,
the material UI slash core slash card.

Let's copy this and paste it two more times. This
will be called media and this will be called content Actually we need with styles as well.
So let's import that. Material UI slash courses slash styles slash with styles. Let's create
a styles object, which will take the theme. So I'm not sure if we're going to use the
theme, but let's just take it anyway. And I'm going to leave it empty for now. And here,
let's say, we're going to make it a functional component, because we don't need to manage
any state or do any have any methods.

So we'll, we'll make this a functional component. So
let's say const. Scream skeleton equals is going to take some props. We'll do parentheses,
curly braces here. And let's pause that for a second say scream skeletons dot skeleton
dot prop types, which is going to have the classes from with styles. So this is going
to be prop types, whoops, prop types.object.is required. And here we need to say export default,
with styles, styles, and we're gonna pass our screen skeleton. Alright, so here, we
need to do our fake chord. So say, let's bring in the styles First, the classes rather. So
const classes equals oops, classes with two s's equals this dot props. And here, I'm going
to say return fragment, inside the fragment, I'm gonna put the content, I mean, I could
put the whole thing here, but it looks cleaner when I put it in a variable.

So say const
content. And here, we're gonna have our card, it's going to be like an empty card. And inside
there is like a blue div here and a gray div here and this image right here. But of course,
we need multiple ones. And I want to fill up the screen. So just in case, I'm going
to put five which fills up the screen. And of course, if there's three later, they're
gonna see that there's only three. But for now, I'm gonna put, I mean for the loading,
we're gonna put five of them. So the way we do this, we can say, so content equals, we
can do can use array dot from.

And here, we can pass some attributes to this array, and
I only need the length of five. So this is basically like a for loop. But, but more efficient.
So here, we do the map on this array that we just created. And we do item. And we're
going to need to actually more than two parentheses here. So item, and I'm only saying item just
to access the index, we don't need the item, there is no item actually. And here, let's
do parentheses, we just outright return stuff. Sorry, let's do card, I'm going to give this
class name of classes card, because we need this to style these depths. And I'm gonna
give it the key of index. And this is why we need index. And here we're gonna have card
media, which is the non image image with a class name of classes dot cover.

And here,
we will say we'll give it the image, which is the no image. Oops, I'm gonna close that
like this, because there's no content in here, let's say cod content. Let's give this a class
name of classes dot call this card content. Let's close this. And here inside the content,
we're gonna have these big divs. So so far, what we have is we have this card with this
image, but there's nothing here. So what we want to put, I want to put a blue div here,
and then a gray div, and then two full lines and one half a line. So it gives the illusion
that there is some content that's being rendered right now, but actually, it's just a fake
skeleton.

Alright, so here, I'm gonna, the first diff, these are just divs. And we're
going to style them. So say, div class name. I'm going to give this a classes dot handle,
because this is the placeholder for the handle. I'm just going to copy these paste. What is
it four more times to four more times. So this is going to be the date, because that's
what's under the handle. And these two I didn't get to do Ctrl D, and I'm going to call this
full line is that the two four lines and this is going to be the half oops, half line like
this. So let's actually style this. So up here in the styles, I'm going to use Flexbox.
To make sure that they, they are arranged properly, one on top of the other. So for
the card, yeah, so we gave this card, we're going to style this card itself. Let's give
it a display of flex a margin bottom, just like the actual cord of 20.

A position to
it to give a position No, I don't think so. Alright, so let's do a comma. And here we
have our chord content. For this, I'm going to give it a width of 100%. Because by default,
it takes the minimum width. Absolutely, this needs to be a string. kind of confusing jumping
from CSS, back to JavaScript back to CSS. Alright, so flex direction, and give this
a direction of columns.

So they stack up on top of the of each other. And I'm going to
give it a padding just like the actual card of 25. And here, let's style the image to
cover we're going to give it a minimum width, otherwise is going to be not visible at all.
So of 200 and an object fit of 200 of 200 cover, even though I know that this image
is actually a square image. But in case the dimensions changed, I don't want it to be
like stretched or like kind of shrank. Here, we're going to style the handle. So handle.
So guys, these are divs.

So by default, they take zero width, so we need to give them a
width. I'm going to give this a hard coded width of 60 pixels, and the height of 20 pixels.
And the back background. Let's just say background colors, the background. And here I'm going
to give it the color from our theme the primary color. And if we go to our theme right here,
where is the Utila theme, we need to access this property. So we need to access the palette
dot primary dot main. So back to our skeleton here, let's say theme dot what is that pilot
dot primary dot main. And here we need our theme to access that. So let's spread the
theme. And then do comma. So this will have the blue like a link word. And here let's
give it a margin bottom. Otherwise, they're gonna stick to each other. Let's give it seven.
Alright, let's let's save let's see what this handle looks like. Alright, there's a problem here cannot read
property. Props of undefined. Oh, this is not a class based component.

So we don't use
that this keyword. Let's go back. Let me reload. Alright, so we see. Okay, we can actually
use Redux to pause our animation at that state. So we can just go here, go back one step,
actually here. Alright, so we can pause at the loading of the data and we can see our
skeleton. Alright, so this looks cool. Not bad, we need to add the other ones. Because
if we don't style them, they're here but they're gonna take zero space.

So let's actually style
the full What is it now the date. So the date I want to give this a should we give it I
think we should give it a like smaller height, because it's kind of a smaller font. So let's
give it maybe 14. And should we give it I think we'll give it more width. Let's do 100
for the background color I want to give Hey gray, so we can say okay, I'm gonna use RGBA.
So I'm just gonna give it a black with the with opacity.

So not point, I think not point
three with do. And let's carry on and actually style the rest so we have the full line. Now
this will take a height of 15 because this is a bigger font size. And for the width,
we're going to give it a percentage value. So I'm going to give it 90%. I could give
it 100 by four to give it 100 is going to come away here and that Not our actual actual code looks like. Let's
give it a margin bottom margin bottom of 10 pixels. Actually, I forgot to give this a
margin bottom margin bottom, give us seven pixels or 10 pixels 10 pixels. Now we have
the half line, which is going to have the same height, it's going to have a width of
actually 50% is going to have a margin bottom, the same one. All right, let's save. She's got to our app. Let's go back to the
loading state. And interesting, we don't see the other depths. To get this depth, oh, we
didn't give it a color, of course, as take this background color here to control or like
Altair, and then paste it.

Let's make this a bit darker. So here we'll do Ctrl D and
give it naught point four. Let's save. Alright, let's look at our app. Let's go to Redux go
back to the loading. Actually, I want it to be much darker than this. So let's give it
nonpoint. Thanks, six, we'll do save. Let's go back
to our loading. Okay, so this is a health line as well. So make a mistake. So full line.
Oh, yeah, this needs to be half line, the way CSS works is that it takes the latest
one, so ignore this. Yeah. So this is how offline not for loan. So it's save us go back. All right. I saw for a second
by looked cool. All right. So this looks perfect, I think. Okay, you see the difference? Now
it goes from here to here. Maybe the user, the user dev needs to be a bit shorter. So
here, the handle. So here, let's give it a height of 18.

Okay, yep, this is more. It
makes more sense this more appropriate. All right, cool. So if we were to just play, press
play, and if we're to reload, this looks so much better. And even if there is some sort
of, like delay, it doesn't, it doesn't feel like there's any like delay from from the
server to the client. Alright, let's make the profile skeleton as well. So let's go.
Let's go here and utils and create another file called profile, skeleton, dot j, s. And
let's go What do we need that you need in the user. So here when we are loading, they
need to say, profile skeleton. And let's import that.

So here from the same directory, select
this control DSA profile skeleton. Let's go to the home as well on here. So profile profile,
fuckin type skeleton. Right here, when we are loading the profile, actually, this is
going to be inside the profile. So oops. So cut that and let's go to profile here in profile
profile. Here, let's import it. Actually, we go back one more level. And right, right
here, so in the loading, say, profile skeleton. And actually, a lot of the styles that are
going to be used in the profile skeleton are going to be the same as the styles in the
profile.

So we can just cut all these these styles and put them in the global theme. So
cut that and spread the theme like this so we can still access them. Let's go through
the theme. And at the bottom here, let's put a comma and paste all that stuff. And actually,
you could do the same thing for static profile. So here just select the entire thing and just
remove it and spread the theme instead. And let's save and make sure that we didn't break
anything. Our theme is not defined. And theme.js Oh, okay. has to be this okay. So this Yeah,
we can't refer to it like that we can just copy the value.

So this let's go here. Yeah,
okay, because our screen skeleton doesn't have anything yet it doesn't export anything
yet. Let's start creating. With the snippets, I'm going to do RFC E, tab. And change the
syntax to const profile skeleton to the arrow syntax. And we're going to need prop types
we're going to need with styles, slash core router, style slash with styles. We're gonna
need the no image port no IMG from we go back to levels, or one level images slash node
dash image dot png.

Here we need the paper just like the actual profile from paper from
material UI paper. And we're going to need the same icons. So let's go to the profile.
And let's get let's get the all the icons here. And the only ones we don't need all
the return and the Edit because we don't have a logout and edit button. Here let's see movie.
Oops. No, we let's declare styles const styles equals theme and returns nothing for now let's
do prop types. So profile, skeleton dot prop types, equals I'm gonna have a classes prop types.object.as required. Yeah, that's
it just classes. Let's get these classes. Props like this without the disk keyword.
And here let's do paper with a class name from the global classes, classes dot paper.
And here kind of similar to the profile so so there's actually like really similar to
the profile except the buttons. Class Name classes dot profile. And inside of here, we're
going to have the image wrapper, which is just actually a normal String class.

So dot
image wrapper. And here we'll have image with the source of no IMG given alt profile, oops
profile, the class name of profile dash image. Here we could put a horizontal ruler. And
here I say dot profile details, we have these from the proof from the global styles. Here,
let's put a div with a class name of classes dot handle. HR to make some space is that
a another div with a class name of this is going to be of two full lines because this
is going to be a fake bio. So as to classes dot full line. Just going to copy this one
more time. Copy and paste it and put the HR and here we're gonna put the location icon
so location on the color of primary. And we can put like a placeholder word or we can
put a place to hold a div.

I can like we can even put some word in there. So I'll put location
like this. And here let's put HR and here we'll put the link. So the Websites link.
And you can omit these, by the way, guys, because maybe a user wouldn't have these at
all, I'm just going to put them, you know, just for reference. So if you want to not
use them, if you're just like skip, like, or like not use these. So I'll put the link
icon, I'm just gonna put a dummy website, so HTTPS, colon slash slash website, Comm.
But another HR, and here we put the join date. So calendar today, they call of primary that's
going to be joined, they date. So let's style these placeholders.

So here, we spread the
theme, so we can use it here for the handle, it's gonna have a couple of things gonna have
a height of 20. By the way, don't forget that the rest of this stuff is already styled from
the global theme. So just style the image or the handle rather, it's gonna have a background
ground color of the, the blue, so we can use the same palette, so themed palette, that
what is a primary, not main, we're going to have a width of 60.

Here, we'll have some
margin to actually adjust margin. So margin. So the first one is the top, let's do a string.
So I give it seven on the top, so seven pixels. And on the right and left, I want to give
it auto. So right it's going to be auto, auto bottom, actually that the top is going to
take seven not that. So the top zero, I mean, the bottom is going to take seven.

So here
I'll say, seven pixels. And then here for the left, I'm going to put auto. So actually,
that set the handle next thing is we style the the full line, so let's do full line. And here we're gonna have a height
similar to the God stuff 15, and the background color. And we're gonna have the same grace.
So RGBA 000, and here is 0.6. Let's give it a width of 100%. And let's give a margin.
So here we need. So I think you're on the top, although on the on the right. And on
the bottom. Actually, could we give just the bottom, let's try just the bottom, I think
there's the bottom would work.

So I'm just going to give 10 on the bottom. And yeah,
let's copy all of this space to call this half line. It's gonna have the same height,
the same color, but the width will be 50%. And the margin bottom will be the same. Let's
save all of this. And let's look at our AP classes dot paper is a problem cannot read
paper of undefined. Oh, it's because here we need to say with
styles, because we don't have classes otherwise. So past styles. And we passed the skeleton.
Alright, let's go back to our app. Go back on the profile loading. Cool. So get the two
full lines for the bio and these icons and the location. So press play. We just reload
our app. Go it looks fine. These, by the way the snap in is because we only have four screens.
So we get to this scroll bar, which pushes the content and then once the content loads,
it goes away.

So once we have more screens, this snap in is not going to happen. Alright,
so we're done with the skeletons. Yeah, actually, guys, we're done with the app. So now that
our application is done, we can actually bundle it up and deploy it to Firebase. First of
all, we could build it out and test it first. Sometimes there's production errors that you
don't foresee. So what we're going to do in the app in the terminal, we're going to run
NPM run build, which is a script that comes already already in create react up applications.
Now is going to build it to this build folder. Alright, now that it's built, so everything
is here the static files And everything, we could see the into that.

And I have this package
this tool called live server. And you could just run live server in that directory. And
we get a problem. And the problem is the server responded with status 404. Okay, so what is
trying to do is trying to get to the is trying to get Ryan to this I forgot to fix this is
trying to get our resources from localhost from the same origin. And the problem is like,
our proxy only works in development. So we can, we need to actually set up a way to tell
axios to always send requests this instead of the local, not local host or the machines
IP. So here in app j, s, so I'm just going to say, Here axios dot default, dot base URL
equals and we just give it this URL. And this should fix that problem.

So let's again, build
it. pm run, build. Alright, let's run it again. Cool, it works, we get our data, no errors,
and we get the users can even like go to the Users page. And the Users page doesn't work.
Oh, okay, we get a cross origin error. So this is a course error. Actually, this is
my bad this is from the server. Let me fix that right now, actually, so in the functions,
and if you've done only the React part, then don't worry, I'll fix this. And it will, it
should work for you. If you've done your own functions, then go to index JS in your functions
directory. And here Actually, let's go into functions, we need to install something called
course. So npm install course, was just add some headers that tell our application that
you can give these resources to any anyone that requests them.

So now that it's installed
here, we can say const. Course equals require course like this. And we just need to tell
our Express app to use this middleware. So here we say course use, I would just I mean
up us, and we pass course and we call it here like a function. So let's save. Let me deploy
this function. So Firebase deploy. Okay, now that it's done installing, or deploying, rather,
we could reload our app. Since seems to get the user's details. Okay, it was just some.
Sometimes when you deploy on Firebase, it takes some time for the code to work. And
it works a bit weird at the beginning. All right, so everything works, fine. I can log
in. So let's try to log in here, just to make sure that everything works.

And I do login and everything is fine. Cool.
Let's actually deployed to Firebase. Now you go to Firebase, go to your app. And if you
don't have an app, you can create a new one, you can go back to part two of this series.
And there we set up Firebase tools and everything related to that, go to hosting. And I've already
enabled it because I've already tested the host, you know, I don't want to have like
some problems on the video, even though I already had a couple. So you could just click
Enable, and it will work. And let's go to our app here. Let's stop the development server
or like the live server, go to the root directory. And here we're going to initialize Firebase
up.

So let's do five days in net, just like we did for our Cloud Functions. Here. Let's
say yes, I want to proceed. And here we want to use the hosting. So space on hosting and
press Enter. And select this up. Do you want to use No Actually, we don't want to use the
public. We want to use the build directory. That's where our build files are. So we say
build, configure single page up. Yes, we say this. already exists. overwrite. Yes, overwrite
it.

Cool. So we've already built our app, we could just run Firebase deploy. And if
you want to make a change, you just make your change and you run NPM run build, you build
your your app, and you just run Firebase deploy a new will deploy it. Alright, so it's done
deploying this is the URL head control and I click it. Whoops. Alright, there we go.
So we get our application is deployed. Let's try to log in. All right, the login works. Everything works.
I can post the screen Hello from deployed up Submit it, and it works. Cool. All right,
so this is deployed. So we're done with this project completely. Guys, please any feedback
anything you want to know anything any praise, likes subscribes, please feel free to and
let me know in the comments if what you want me to do like a video on any framework.

I've
got a bunch of video ideas right now. So feel free to like, you know, contribute. So thank
you for watching and I will see you soon. Bye.

As found on YouTube

You May Also Like