
No Comments Yet
Be the first to share your thoughts and start the conversation.
Be the first to share your thoughts and start the conversation.
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
This lesson focuses on how to create and manage an All Users page using Syncfusion's grid component in a React application. The instructor demonstrates how to set up the grid with user data and customize its appearance, ultimately retrieving real user data from a database.
00:00:02 To get started working on the All Users page, first navigate over to it, and then open it up right here within our code base.
00:00:10 We have already added it to the routes.
00:00:12 So if you check it right here, you can see that you can access it by going over to All-Users, which is exactly where we're on right now.
00:00:19 And here, we'll use Syncfusion's grid component.
00:00:24 They have this very nice guide that shows you how we can install it and set it up.
00:00:29 But basically what you have to do is use the grid component, pass the data source to it, and then render a couple of different columns for the different
00:00:39 fields that you want each one of your rows to have.
00:00:41 So let me show you how we can make it work.
00:00:43 First things first, I'll change the class name right here from dashboard to all-dash users.
00:00:49 And then instead of trips page, I will say manage users, and we can change the description to something like filter, sort,
00:00:59 and access detailed user profiles.
00:01:05 Perfect.
00:01:06 Right below the header, I'll render the Syncfusion grid component.
00:01:11 This grid component will be coming from right here at the top, add syncfusion forward slash ej2 react grids.
00:01:20 Tables are not easy to work with.
00:01:22 So let me show you what we can do with this grid.
00:01:25 First things first, you have to pass a data source to it.
00:01:28 So let's say data source is equal to, and now what you need to do is just basically pass an array of different objects into it.
00:01:37 But instead of declaring it right here, for the time being, we can use the static data coming from our constants.
00:01:43 So I'll simply say users, and we'll import those users coming from constants, index.js.
00:01:50 It is basically just an array of three different users that I want to render right here on the page.
00:01:56 And then once we render them, we can switch it over to use real data.
00:02:00 And there we go.
00:02:01 Already, just by doing that, you can see a table.
00:02:04 Of course, tables are better viewed on desktop devices.
00:02:07 So if you check it out, it's pretty cool, right?
00:02:10 You get the ID, the name, email, image URL, date joined, itinerary created, and a status of either user or an admin.
00:02:19 Now, I'll collapse this just a tiny bit so we can see the code, but also the rest of the stuff.
00:02:25 As you can see, it is mobile responsive, but we can definitely make it so much better.
00:02:30 So, within it, I will render a columns directive, but make sure that you spell it columns plural, and use the one coming from React Grids.
00:02:40 Next, right within it, you can render each individual column directive.
00:02:45 So import that one too, and then self-close it.
00:02:49 Within it, you can specify exactly what you want each field to have and how you want it to look like.
00:02:55 So I'll give this field a name equal to name.
00:03:00 I'll give it a header text equal to name with a capital N.
00:03:05 I'll give it a width of about 200. And I'll even align the text on the left by saying text align is equal to left.
00:03:14 And the second one will be just a column directive.
00:03:18 Not columns, but rather a column.
00:03:21 So you'll also have to import it right here at the top.
00:03:23 And you can see, now that we have decided to manually decide how we want to present all of these different columns and rows,
00:03:30 now we only have one column with names John, Jane, and John.
00:03:34 What you can do is also say grid lines and set it to none.
00:03:39 That way it looks a bit cleaner.
00:03:41 You do this to the regular grid component.
00:03:43 Now, what else can we do with each one of these fields?
00:03:46 Well, we can also define a template that allows us to choose exactly how each one of these will be rendered.
00:03:53 So, for the template, I will open up a callback function inside of which we get access to the props, which will be of a type userData because we're mapping
00:04:04 over the users.
00:04:05 So for each one of these props, we want to automatically return a div.
00:04:10 And each one of the divs will have a class name equal to flex, items-center, gap of 1.5, and a padding x of 4. And within it,
00:04:23 we want to display an image.
00:04:25 So instead of simply displaying a name, we want to render an image with a source of props.imageurl with an alt tag of user,
00:04:37 a class name equal to rounded-full, size of 8, and an aspect of square.
00:04:46 If you do this and reload, you should be able to see a profile photo for each one of our fake users.
00:04:52 And below the profile photo, you can render a span element that'll render the props.name.
00:04:59 Perfect.
00:05:00 This is already better than what we had at the start.
00:05:03 It really shows how customizable it is.
00:05:06 Now, let's also declare another column directive right below.
00:05:10 The future ones will be even simpler.
00:05:12 They'll have a field.
00:05:14 This one will be for the email.
00:05:16 so that it knows how to match the data.
00:05:19 See, this value right here matches exactly the value of the key in that specific object in the array.
00:05:27 So the first one was the name, and now we want to show email addresses.
00:05:32 So the field is email.
00:05:34 The header text will be set to email.
00:05:38 The width can be maybe set to 150. And text align can be set to left.
00:05:44 And you put this column directive properly within the columns, not outside of it.
00:05:50 You should be able to see it appear right here immediately.
00:05:53 What we can do next is just copy that column directive.
00:05:57 and maybe duplicate it two more times.
00:06:00 For the third field, I will render the date joined and change the header text to date joined with a width of maybe 120 will be enough.
00:06:12 So now we see January as well.
00:06:14 And maybe the next one can be trip created, or I think in this case it's itinerary created.
00:06:21 We can again say itinerary, or maybe trip is shorter, created.
00:06:25 And this will be when the trip was created.
00:06:28 So about 130 characters is enough.
00:06:31 So if I save it, now you can also see trip created, but I need to spell it properly exactly as to how we have it in the user data.
00:06:40 So if I head over into users, it is itinerary created.
00:06:44 How many of them have we created?
00:06:47 So this user has created 10, 4, and 8. And finally, and most importantly, we need to show the status or the type of the user.
00:06:55 So I will duplicate this column directive one more time right below, and I'll call the field status, a header text of, maybe here we can say type of the user,
00:07:07 width of about 100, And for the template, we can once again get access to the props of the user data.
00:07:17 And then for each one, we can return an article that we're going to close.
00:07:23 And within it, we can render a div.
00:07:26 Within the div, we can render an h3 that will render the props.status.
00:07:34 So here, you can see that now, if you reload, you can see the type of either the user or the admin.
00:07:41 But let's also style this a bit differently to make it like a chip component within it.
00:07:46 First, I'll style the article by giving it a class name equal to, and I'll make it a dynamic CN class name that'll always have a status column class,
00:07:58 but then depending on the props.status, which I can just destructure from the props right here.
00:08:06 So I'll simply get the status out of it so we don't have to repeat ourselves too much.
00:08:13 If the status is triple equal to user, in that case, we'll return the BG success of 50, else we'll return the BG light of 300. So if you save that,
00:08:29 you should be able to see a light background on each one of these articles.
00:08:33 Now, right below within this div, I'll also give it a class name.
00:08:38 I'll also make it a CN.
00:08:40 It'll have a size of 1.5 and rounded-full.
00:08:46 And if the status is triple equal to user, I will then give it a BG success of 500. Else, we can give it a BG gray of 500. So if you save that,
00:09:01 you'll now see that little dot that we have right here.
00:09:04 And now we can style this H3 within it.
00:09:08 by giving it a class name of CN, font-inter, text-extrasmall, and font-medium.
00:09:17 And finally, if a status is triple equal to user, in that case, text success of 700, else, text-grey of 500. So, let me style this properly.
00:09:34 And if I go ahead and save this, you can see that now the text matches the color, but it doesn't yet look good, and that's because this div should not
00:09:43 close the H3.
00:09:44 Rather, the div should be a self-closing component, as it is just the dot that appears right here before the user.
00:09:52 So you can see how customizable the table is.
00:09:54 You can show the photo within it.
00:09:56 You can change how much space each one of these fields takes.
00:10:00 And you can also change whatever is presented right within each one of these rows.
00:10:05 Perfect.
00:10:06 And believe it or not, that is it.
00:10:08 A fully functional table where you can actually hover over fields and implementing filtering or sorting and pagination within it is also super simple.
00:10:17 I'll show you how we can do that once we actually get more users.
00:10:20 But for now, I actually want to load up the real users right here, not these fake ones.
00:10:26 So what we can do is head over into app, apprite auth.ts and create a new function called getAllUsers.
00:10:38 We can do it right at the bottom.
00:10:40 The goal of this function is to fetch all of the user.
00:10:43 So let's export a new async function called getAllUsers.
00:10:51 And make it equal to an asynchronous function, like this.
00:10:55 So export const getAllUsers is equal to an asyncError function.
00:11:00 And we can open up a try and catch block.
00:11:04 In the catch, I will simply console log the error, saying error fetching users.
00:11:13 And in the try, we need to list the documents coming from the database.
00:11:18 So I'll say const, destructure something, and make it equal to an await call to database coming from AppRite.listDocuments.
00:11:31 As before, we have to tell AppRite from which database ID to get it.
00:11:35 And that database ID is stored in the AppRite config.databaseID.
00:11:40 Then we have to specify from which collection, so we'll say AppRedConfig.
00:11:45 This time, it'll be a user collection ID.
00:11:48 And finally, we need to provide a query to fetch this.
00:11:52 In this query, I want to limit the amount of users that we get back by a specific number.
00:11:57 Let's say five for now.
00:11:59 And then to implement the pagination, I also want to offset the query by a specific number, let's say 2. Essentially, with the limit and the offset,
00:12:09 you are implementing the pagination.
00:12:11 Why?
00:12:12 Because if the limit is 10, and you're offsetting 5, you're basically dividing this into two pages.
00:12:18 One that has 5, and page 2 that has the other 5. Hopefully this makes sense.
00:12:24 So to make this pagination dynamic, as the params into this function, we can accept a limit of a type number, as well as the offset of a type number 2.
00:12:35 So instead of hard-coding them, we can just declare them right here, limit, and offset.
00:12:42 Now, the call of this function will give us back the documents.
00:12:46 And these documents we can rename to user because that's what they are.
00:12:50 And we also get back the total number of documents.
00:12:53 What we can say is if total is triple equal to zero, we can just return users equal to an empty array and total equal to the total,
00:13:04 which in this case will be equal to zero.
00:13:06 But in case we do get some users, we can then return the users equal to users as well as the total equal to the total we're getting.
00:13:16 Hopefully this makes sense.
00:13:17 So now, the only thing we have to do is call this function within the allUserStable.
00:13:24 right here at the top.
00:13:26 Instead of declaring it right here, we'll use the React router's new functionality to fetch it before the page loads by implementing a loader.
00:13:35 So above the function, I'll say export async function loader or you can use es6 to say export const loader is equal to an async function And here,
00:13:50 we can get access to those users and the total number of users by awaiting the getAllUsers coming from AppWriteAuth.
00:14:00 And let's say we want to limit it to 10 and offset by 0 at the start, because we're in the first page.
00:14:07 Once you do that, we can just return an array of users as well as the total number.
00:14:13 Basically, what we have done is we have exposed it right here to within our function.
00:14:18 So let's destructure the loader data of a type route coming from react-router-types.
00:14:27 And this is going to be coming from all-users.component-props.
00:14:33 And then we can just say const users and destructure them from the loader data.
00:14:39 Here, we have a bit of a warning saying that users does not exist on type get all users.
00:14:44 Let's see if we're properly returning it.
00:14:47 We are here, but we also can return it in the cache.
00:14:51 So if something goes wrong, we can return the users as an empty array, and the total also equal to zero.
00:14:59 If we do this, then it'll know that always there's going to be a return of users and total.
00:15:06 Also, let's fix this route import because I can see that it's coming from the wrong file.
00:15:11 Basically, it should be coming from just dot slash plus types forward slash.
00:15:17 In this case, we can get it from all users and we have to specify that we're importing a type of route.
00:15:26 Perfect.
00:15:27 So now we're getting the users and you can immediately see that instead of having the fake users coming from the constants,
00:15:33 which we can now completely remove, now we're getting a single user from a real database.
00:15:40 There are a couple of things we have to fix though.
00:15:42 The name and the profile photo are looking good.
00:15:45 We can give some more space to the email address.
00:15:48 So let's scroll down to the email address and maybe give it a width of 200. That'll give it some more space to breathe.
00:15:55 After that, we have the date joined.
00:15:58 So I'll just rename this to joined at, because I believe that's how we're saving it into the database.
00:16:04 And you can see that now we're getting that date joined.
00:16:07 And we also need to parse it a bit better.
00:16:10 Do you know how to do that?
00:16:13 Well, you need to create a template for how you will render it.
00:16:17 So just create a template, have a callback function where you get the props, in this case, the joint add date, so I'll just destructure the joint add from it,
00:16:28 and then we can just return what you want to show, in this case, I'll call the FormatDate function coming from LibUtils and then I'll pass this JointAdd
00:16:40 right into it.
00:16:41 If you do that, you'll see April 23rd, 2020. Let's also give it some more space to breathe just so we can see it a bit better.
00:16:49 April 23rd, 2025. Beautiful.
00:16:52 Did you see how simple that was?
00:16:54 We can also say that JointAdd is of a type String.
00:16:59 Perfect.
00:17:00 So I was just able to take this piece of data from the database, take its field, and then nicely present it right here.
00:17:08 I don't think we'll need the trips created thing, so I will just remove it from now because we're not actually storing it within the database.
00:17:15 But what we care about is, of course, the type of the user, which in this case is the admin.
00:17:20 So with that in mind, we now have our first and only user, and we have a table with which we can check it out.
00:17:28 We can head over to the dashboard and check out our only user.
00:17:31 Looks pretty cool, right?
00:17:33 What do you say that we go ahead and sign in as the second user as well to see the differences?
00:17:37 I'll log out.
00:17:38 We have this great-looking sign-in page.
00:17:41 And I'll log in with my second JavaScript Mastery email address.
00:17:44 And now, if I try to head over to the dashboard, you'll see that I'll be redirected back to the homepage.
00:17:51 So, later on when we implement the public-facing website, I'll be able to check it out.
00:17:55 But right now, as I'm a mere public user, I cannot see the admin dashboard, which is its whole point.
00:18:01 So open up Inspect Element and head over to Application and clear your cookies.
00:18:08 Session storage as well.
00:18:10 And once you clear it, just reload your page.
00:18:13 Or just manually head over to the sign-in.
00:18:15 I've logged back in with my admin user.
00:18:19 So if I head over to All Users, you'll be able to see this second account that says JavaScript Mastery.
00:18:26 I can see that the image is not loading properly.
00:18:28 But I think we know how to fix that, right?
00:18:32 We have to head over to where we're rendering that image, and we have to give it a refer policy of no refer.
00:18:40 If I save it and reload, you can now see that we have two of the same profile photos.
00:18:45 For you, it should be something different if you used a different profile.
00:18:49 But what matters most is that the type of these two users is actually different, and the email address as well.
00:18:56 And they're both showing on our table where we can match the users.
00:18:59 So that means that our all users table has now been completed.
00:19:03 So now that we have the basic dashboard, the authentication system, and our users are actually logged in, is the time that we actually create the trips.
00:19:13 That's what this app is all about, right?
00:19:15 So, let's focus on creating the form that'll make all of that possible.