
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 show the list of questions, let's first create a server action that'll allow us to fetch those questions.
00:00:08 First, let's head over into the action.d.ts.
00:00:12 And here, let's create a type for the server action.
00:00:15 I'll call it an interface.
00:00:18 Get user questions params.
00:00:22 And I'll make it extend the paginated search params.
00:00:26 like this.
00:00:27 But instead of just extending it, I will extend the omitted version, okay?
00:00:33 So you can call the omit on it, and then you can remove the query and the filter from it, as well as the sort, because in this case,
00:00:43 we won't need to filter, query, or sort, but we still want to get the typical paginated search params, and a new one called user ID.
00:00:51 We can do a similar thing with the validations.
00:00:54 So if you head over here, it'll be export const getUserQuestionsSchema and we'll make it equal to paginatedSearchParamSchema.extend and we want to extend
00:01:08 it by the user ID, just like this.
00:01:11 Now we can head over into the user.action.ts and below getUser we can implement the getUserQuestions.
00:01:20 To start doing that, I'll actually just copy this getUser and I will paste it right below.
00:01:26 I'll rename it to getUserQuestions.
00:01:30 We still get the params, but in this case, we won't return the user.
00:01:34 We'll just return the questions themselves.
00:01:37 So I'll say questions is of a type question array, and we'll have the isNext property.
00:01:42 We get over the validation result, check for errors, and then destructure the user ID, as well as the page by default set to one and the page size by default
00:01:53 set to 10 from params.
00:01:56 Next, we want to deal with the pagination.
00:01:58 So I'm going to say skip is equal to, well, take the current page number, decrement one, and then multiply it by the page size,
00:02:06 and the limit will be equal to the page size.
00:02:08 Now, instead of fetching the user, I want to fetch over the total questions.
00:02:14 So I'll say cons total questions is equal to a weight.
00:02:18 question.countDocuments where the author is equal to the user ID.
00:02:23 And once we count them up, I actually want to fetch them by saying const questions is equal to await question.find questions where the author is equal
00:02:33 to the user ID.
00:02:35 And we want to populate, so run the .populate on it, the tags, specifically with tag names.
00:02:42 and also populate the author with its name and image.
00:02:48 Because in each one of these questions, we want to show the author's name and image as well.
00:02:54 We skip it by specific number and limit it.
00:02:57 No need to sort it in this case.
00:02:59 Finally, we figure out if a next page exists.
00:03:03 We can do that by checking if the total questions is greater than skip plus the questions at length.
00:03:10 And finally, we return success to true as well as the questions is equal to JSON parse, JSON stringify questions, and the is next boolean.
00:03:21 This is pretty crazy.
00:03:22 You just saw that I was just pressing tab multiple times and my editor auto-filtered for me.
00:03:27 You might need to pause a bit to also type it out on your own if you're watching this in real time without pausing.
00:03:34 So feel free to pause.
00:03:35 That's totally okay.
00:03:36 But as we have done this so many times, I don't want to over explain.
00:03:41 I just want to make sure that we seamlessly go ahead and implement the rest of the features of this application as we have already learned the ways of
00:03:49 doing that many, many times over.
00:03:51 So let's actually put it to use and display the result.
00:03:55 I'll head over into our profile ID and I'll have to fetch it right here at the top.
00:04:03 We'll do it below the destructuring of the data.
00:04:07 I'll say something like const, these structure the success as the userQuestions success, these structure the data as the userQuestions,
00:04:20 and these structure the error as the userQuestions.
00:04:25 And we get back that data if we call await getUserQuestions, coming from user actions, to which we have to pass the userId.
00:04:37 userId is equal to id.
00:04:40 the page, which is either a number of the page coming from params or the number one.
00:04:46 And finally, also the page size, which will be either a number of a page size coming through props or a number such as 10. That's great.
00:04:57 Let's make sure that this page is fine.
00:05:00 Oh, I forgot to change the actual params right here.
00:05:03 This was supposed to say, get user questions params.
00:05:08 So now it'll no longer complain.
00:05:11 Oh, and let's make sure to get access to the page size.
00:05:15 This page size is coming from search params.
00:05:17 So we can get access to search params from here.
00:05:22 and then destructure it by saying const page and page size is equal to await search params.
00:05:31 Once again, the search params are question mark, ID is equal to something, and then params are just forward slash ID, forward slash something,
00:05:40 okay?
00:05:41 So these are the differences between how params and how search params work.
00:05:48 Great.
00:05:49 So now that we're fetching all that data, we can actually destructure it a bit more.
00:05:54 I'll do it right below.
00:05:56 By destructuring the questions and the is next, which I will rename to has more questions.
00:06:04 And that's coming from user questions.
00:06:06 And now we can use the same data renderer component that we used many times before to display it.
00:06:12 Where did we use it last?
00:06:13 Oh, it was in the right sidebar.
00:06:15 So I'll actually copy this data renderer.
00:06:20 and let me paste it right here below within the first Tabs content.
00:06:25 So see this Tabs content?
00:06:27 I'll make some space right here and I'll put it right here within the Tabs content but I will remove the way in which we render out each element because
00:06:37 that was a long way.
00:06:39 So what we want to do is just return a div.
00:06:42 And within that div, we'll later on display the questions.
00:06:46 But before we do, let's just make sure that we're passing the right data to it.
00:06:49 As the data, I'll pass questions.
00:06:52 As empty, I will pass the empty underscore question state, which we can import.
00:06:59 As success, I will pass over the user questions success.
00:07:04 And as error, I will pass over the user questions error.
00:07:09 So now we can see questions but the only thing that's remaining is for us to actually map over them.
00:07:15 So let's give this div a class name equal to flex w-full flex-call gap of 6 and within it we can say questions.map where we get each individual question
00:07:32 And for each question, we automatically return a question card component, which we have already implemented before.
00:07:41 To the question card, we have to pass a key equal to question dot underscore ID, as well as the question itself.
00:07:49 So I'll say question is equal to question.
00:07:51 If you save it, you should be able to see three cards appear right here.
00:07:56 And just like that, check this out.
00:07:58 We're displaying the same question cards, but this time only showing the questions that that user has posted.
00:08:05 This is great.
00:08:07 Now, just to make sure that the pagination is working, let's try to change the page size to something like two, which would allow us to see two posts on
00:08:15 that page.
00:08:17 And it works.
00:08:18 And then just below it, below the data renderer, we can render the pagination component.
00:08:26 coming from components pagination to which I will pass the page equal to page and is next equal to has more questions.
00:08:35 And just like that, immediately you'll see a fully functional pagination.
00:08:40 Great!
00:08:41 How crazy that is that we can implement the pagination across all the different places within our app and also display the components that we have created
00:08:49 before but now inside of a totally new layout.
00:08:52 I mean, just look at this.
00:08:54 We're showing the top posts right here, belonging to this specific user, and they're looking great.
00:09:00 So let's go ahead and commit it by saying, implement user's questions, commit and sync.
00:09:08 And in the next lesson, we can show the user's answers.