
Join the Conversation!
Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.
"Please login to view comments"
Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.
Complete source code for this lesson is available at
How did you manage to remove the blur property and reach here?
Upgrading gives you access to quizzes so you can test your knowledge, track progress, and improve your skills.
By logging in, you'll unlock full access to this and other free tutorials on JSM Pro.
Why? Logging in lets us personalize your learning experience, track your progress, and keep you in the loop with new workshops, coding tips, and platform updates.
You'll also be the first to know about upcoming launches, events, and exclusive discounts.
No spam—just helpful content to level up your skills.
If that sounds fair, go ahead and log in to continue →
Enter your name and email to get instant access
##Looks like we found a thief monkey By the way, I liked the trick how you reached till here. You have a good sense of humor. You will improve a lot if you join our course with this passion.
var
(function-scoped, outdated)let
(block-scoped, modern and recommended)const
(block-scoped, cannot be reassigned)_
, or $
let let = 5;
is invalid)myVar
and myvar
are different)string
, number
, boolean
, null
, undefined
, bigint
, symbol
Objects
, Arrays
, Functions
Subscribing gives you access to a brief, insightful summary of each lecture to stay on track.
00:00:02 To put the server action we created in the last lesson to use, let's go over to our profile details page.
00:00:08 That is profile ID.
00:00:10 This is the page that we have left completely intact up to this point.
00:00:14 So right here, let's say const destructure the success, the data, and the error coming from the call of await get user, coming from lib user actions.
00:00:27 And to it, don't forget to pass the user ID.
00:00:33 Now, first of all, we have to make this function asynchronous, since we're using Await.
00:00:38 And second of all, we have to get access to this ID.
00:00:41 Where is it coming from?
00:00:42 Any ideas?
00:00:44 Well, it's coming from params.
00:00:46 If you head over into some profile, like this profile right here, you'll see that it is profile forward slash and then we have this ID.
00:00:56 This is a bit different than having something like question mark ID is equal to this.
00:01:01 That's different.
00:01:02 Here, we only have forward slash and then the ID.
00:01:06 So to get access to this ID, you can simply destructure it from params and say route params right here.
00:01:14 And then you can destructure the ID by saying const ID is equal to await params.
00:01:20 Now, if this doesn't exist, then we cannot render it.
00:01:22 So I'll say, if no ID is found, then simply return a not found page coming from next navigation.
00:01:29 So this is a redirect.
00:01:31 Else, let's figure out if the page we're looking at is the currently logged in user.
00:01:36 We can do that by saying const loggedInUser is equal to awaitAuth.
00:01:43 And this will allow us to let us know if the user is currently looking at his own profile or looking at somebody else's profile.
00:01:50 Like maybe showing an edit button if they want to change their name.
00:01:53 Then we fetch the general profile details.
00:01:56 And I'll say if there is no success, then we can return some kind of an error message.
00:02:01 For now, I will simply do a div that'll render the question mark message.
00:02:07 We can give it a class name equal to h1-bold and text-dark100, light 900. We should never be able to see this error, but just in case we do,
00:02:17 we'll be able to see the error message as well, so we can fix it.
00:02:20 Next, we can destructure all of the most important properties from the data.
00:02:25 So that's going to be the user, the total questions, and the total answers.
00:02:30 And these are coming from.
00:02:33 Now, before displaying the results on the UI, we'll use a date management library to handle the dates, specifically to show when a user has joined their platform.
00:02:42 While we could create a small function for this ourselves or with AI, this time I'll show you how to use a library that is great for managing dates.
00:02:50 So open up your second terminal and run npm install dayjs.
00:02:56 It's a super lightweight library.
00:02:58 We want to display something that looks like this, like a header, an icon, a name, a username, and then some links right here.
00:03:07 So just so we're not repeating ourselves, let's create a reusable component that'll allow us to duplicate those links easily.
00:03:13 Oh, and this is supposed to say total answers.
00:03:16 Perfect.
00:03:17 TypeScript caught that very nicely.
00:03:18 So now I'll head over into components and then I'll create a new folder called user.
00:03:26 And within user, I'll create a new component called profile-link.tsx and run RAFCE.
00:03:33 We'll implement it soon, but for now, let's quickly head over into the global.d.ts and find where we have information about our user.
00:03:42 Oh, I don't actually see our user anywhere here.
00:03:45 So let's create a new interface.
00:03:48 of user and we'll want to make sure to give it all the properties that it has, such as the underscore ID of a type string,
00:03:55 a name of a type string, a username of a type string, an email of a type string, an optional bio of a type string, an optional image of a type string,
00:04:11 an optional location of a type string, an optional portfolio link of a type string, reputation, which is also going to be optional,
00:04:23 of a type number, and then a created ad property of a type date.
00:04:28 We'll use it to decide when a user has joined.
00:04:31 So now if we head back over to our profile page, so that is profile ID, we can start implementing the JSX.
00:04:39 I'll first wrap everything in a section that'll have a class name equal to.
00:04:45 And you know what?
00:04:45 Let's put our browser side by side with our editor so we can see what we're doing.
00:04:49 There we go, this is better.
00:04:51 For now, just a blank screen.
00:04:54 Let's give it a class name of flex flex-call-reverse items-start justify-between and on small devices flex-row.
00:05:06 Within it, we can render another div with a class name of flex flex-call items-start, gap of four, and on large devices,
00:05:18 a flex of row.
00:05:21 Within it, we can easily display a user avatar because we already have that component created, but we'll have to pass it an ID equal to user dot underscore ID,
00:05:33 a name equal to user dot name, an image URL equal to user dot image, a class name equal to size dash 140 pixels, rounded dash full,
00:05:47 object dash cover.
00:05:50 And we can also give it a fullback class name equal to text-6xl and font-bolder.
00:06:01 Perfect.
00:06:02 Now, if you save it, you'll see your image right here, but you'll see that it says that image does not exist on type model any.
00:06:10 Interesting.
00:06:11 So this is referring to our user that we're getting here.
00:06:15 So we might need to head over into the getUser.
00:06:18 And here, I will now remove this type of, considering that we have added this user type or user interface to our global.d.ts.
00:06:27 So now, back in the page, it'll no longer complain because it knows that the user has those properties.
00:06:34 Let's head over below this user avatar and display a div with a class name of margin top of three.
00:06:42 And within it, we can display an h2 that'll render the user.name.
00:06:47 And you know what?
00:06:48 Just so we don't have to repeat ourselves, username, ID, image, and so on, I will just destructure all of these properties from the user.
00:06:56 So I'll say const, give me the underscore ID, the name, the image, the portfolio, the location, the created ad, the username,
00:07:08 everything I can think of.
00:07:09 I'll simply get it from the user.
00:07:11 And then we can now remove this user.
00:07:15 And just say ID, name, image, everything.
00:07:19 Perfect.
00:07:20 Let's style this name a bit by giving it a class name equal to H2 dash bold, text dash dark 100, light 900. Below it, let's render a p tag that'll render
00:07:36 the at user dot username, or in this case, it is just username.
00:07:41 And let's give it a class name of paragraph-regular, text-dark200, light 800. There we go.
00:07:51 This is looking nice.
00:07:53 Below this p tag, still within the same div, I'll create another div for those links that I was telling you about.
00:08:01 So let's give it a class name, equal to margin top of 5 divided a bit from the top, flex, flex-wrap, items-center, justify-start,
00:08:14 and a gap of 5 in between the elements.
00:08:17 And within it, I can now check whether a portfolio exists.
00:08:23 And if it does, I will display a profile link coming from components, profile link.
00:08:30 We'll develop it very soon, but for now, let's just pass the necessary props to it.
00:08:35 such as the image URL equal to forward slash icons forward slash link.svg and href of where that link will lead.
00:08:44 This is the portfolio.
00:08:46 And then the title, which will be equal to portfolio.
00:08:49 We can now duplicate this two more times.
00:08:52 One, two.
00:08:55 In the second time, we'll check for the user's location.
00:08:57 And if a location exists, then we'll pass over the icons.location.
00:09:02 And in this case, we won't have an href because location is not clickable.
00:09:06 And finally, for the third one, we won't do any checks.
00:09:09 I will just render a profile link component saying image URL is icons, calendar, and I'll give it a title equal to dayjs created at .format m-m-m-m y-y-y-y
00:09:28 and we're gonna put that within a string Of course, make sure to import dayjs right at the top.
00:09:34 So that'll be import dayjs from dayjs.
00:09:39 Perfect.
00:09:40 So now we can see only one link because this user doesn't yet have a portfolio nor the location, but I'll show you how we can do that later on.
00:09:47 Now, right below this div that contains these links, we can do another check and that is if a bio exists.
00:09:55 Bio is also coming from the user, so I will have to destructure it right here.
00:10:01 And then I'll check if the bio exists, then render a p tag, and this p tag will render the bio.
00:10:09 And it'll have a class name equal to paragraph dash regular, text dash dark 400, light 800, fit a margin top of eight.
00:10:20 Now we want to go two divs down and create one final div.
00:10:26 This one will have a class name equal to flex justify-end on Mac's small devices margin-bottom of 5, on Mac's small devices w-full,
00:10:39 and on small devices margin-top of 3. And within it, we want to check if the logged in user, question mark dot user, question mark dot ID,
00:10:50 is equal to the ID of the profile we're currently checking.
00:10:53 And if that is the case, then that means that the user is currently looking at their own profile, so my profile page.
00:11:00 In that case, we want to add a link that'll have an href of forward slash profile forward slash edit.
00:11:07 And we can render a button coming from components UI button.
00:11:12 That'll say Edit Profile.
00:11:14 Let's style this button a bit by giving it a class name of paragraph-medium, btn-secondary, text-dark300, light900, min-h12,
00:11:29 min-w44, padding x of 4, and padding y of 3. Perfect.
00:11:35 We'll look into that very soon.
00:11:37 But for now, let's head over into this profile link component and let's get it implemented.
00:11:42 For this one, we'll use a different color that is not a part of the current theme.
00:11:46 So head over to your tailwind.config.ts if we're using that anymore.
00:11:51 If not, it'll most likely be in the globals.css.
00:11:54 But below the light, simply we'll do something like link of 100. And we can say hash 1DA1F2, and this is the new color we'll use.
00:12:09 So let's develop the profile link by accepting all the props, the image URL, the href and the title of a type props, which we can define right here at
00:12:22 the top by saying interface props.
00:12:26 Let's give this div a class name of flex-center, gap of one.
00:12:29 Immediately within it, we can render a Next.js image field coming from NextImage.
00:12:45 with a source equal to image URL, an alt tag equal to title, a width of about 20, and a height of about 20 as well.
00:12:56 Now you should be able to see just the calendar right here.
00:12:59 Next, if the link is clickable, so if an href exists, then we will render a link component and give it an href of href.
00:13:10 And a target of underscore blank.
00:13:12 So it opens on a new screen.
00:13:14 Typically when you pass an underscore blank, you also want to add this no opener, no referrer.
00:13:19 It's just a good practice.
00:13:20 And we can give it a class name equal to paragraph dash medium, text dash link dash 100. And within the link, you can actually render the title of that link.
00:13:34 We can close it and then if it's not a link, we want to just render a P tag that'll render the title again, but this time not clickable with a class name
00:13:45 equal to paragraph medium text dash dark 400 light 700. So now if you save this, make sure to import the link from next link.
00:14:00 And make sure to properly close this curly brace right here.
00:14:02 Perfect.
00:14:03 So now it says November 2024 is when I created this account.
00:14:07 For you, it'll be something different.
00:14:09 If we now expand this, it's looking good.
00:14:11 I'm not sure what this link at the top right is.
00:14:14 Let's go back to the page to try to see it.
00:14:16 At the top of the profile link, I noticed that we don't have to wrap it in curly braces.
00:14:20 It is just a default import.
00:14:22 And I misspelled the class name right here.
00:14:25 So now if we fix it, it should be good.
00:14:28 Now let's try to console log the underscore ID we're getting, as well as the currently logged in user ID.
00:14:36 That is right here.
00:14:39 So let me copy this part.
00:14:40 And right here before the return, I'll console.log an object with two things.
00:14:47 First, I'll say logged in user ID.
00:14:52 And then second, I'll just render the ID of ID like this.
00:14:58 So if I do that and open up the terminal, this is coming from the server, you'll notice that these two appear to be the same.
00:15:05 6744, ending in ED2.
00:15:08 And what if I add a typeof operator in front of it?
00:15:13 So here, as well as here, you'll see that they're both of the type string.
00:15:19 So what if I try to test their equality?
00:15:22 I'll say are they the same?
00:15:26 And I'll make it equal to logged in user is equal to just the ID.
00:15:32 And in this case, we get true.
00:15:35 So we know that they are indeed the same.
00:15:37 So where is our edit profile button?
00:15:40 Well, it should be right here, right?
00:15:42 So why is this not clickable and why is it not saying edit profile?
00:15:46 Well, if you go a bit up, you'll notice that we imported the link from Lucid React instead of Next Link.
00:15:54 So if you fix this import to Next Link and make it a default import, you'll see that now, instead of an icon, you'll see an Edit Profile button,
00:16:04 which will redirect to Profile Edit, which for now doesn't really exist.
00:16:09 So this is perfect.
00:16:11 Now we have the profile page, or at least we have the profile header, and we also have a link to edit profile.
00:16:17 If you were on another user profile, such as if I go to community and try visit Sujata's profile, you'll see that I don't see that edit profile button.
00:16:26 Now, alongside the profile header, which we have developed right now, the next goal is to implement the stats section.
00:16:34 Right now, we don't yet have the logic to actually account for different badges.
00:16:38 We might do that later on, but for now, let's just do the UI.
00:16:42 We'll do it in the next lesson.
00:16:43 So for now, let's go ahead and commit this one by saying implement profile header, commit and sync, and let's focus on the stats section of the profile
00:16:54 page next.