So we left off by configuring our Drizzle and database and we added our first record inside our courses schema table right here. So what I want to do next is just add a couple of more courses inside of our database so that we can display them on the courses page. And I recommend that you add all of this which you have in your public folder. So Spanish, French, Croatian, Italian and Japanese are the ones that I have added. So let's go ahead inside of the terminal here.
And I'm going to open a new terminal and I'm going to run npm run database studio here. And that will give me an URL where I can look at my database here. So let's go ahead and do the following. I'm going to open my public folder here so that I can see. I already have Spanish added in my courses So let me add another one.
So this is going to be an ID of two. I'm going to add French. And let me just see if I can do this and write French. Can I do that? And slash fr.svg.
Like that. And save one change. There we go. Let's go ahead and do it again. So the third one is going to be creation.
And I'm going to go. Oh, I have to confirm this and then slash hr svg and let's go ahead and add a fourth one and I'm gonna make that Italian and let me go slash it svg and Italian So you have to press enter in the column once you finish writing and then press save change. There we go. So I have Spanish, French, Croatian and Italian. I think four of them are enough for us to create the initial page.
So yeah, we have to manually enter the IDs when we are adding them through the database like this, I believe, but later when they are created through our admin dashboard, we are not going to need to add the ID. So I want you to learn how to use the Drizzle Studio that's why I didn't add the admin dashboard at the moment because it's quite useful because from here you can also delete records so this is kind of a super admin dashboard which you have, which is your database. Great, so just ensure that in your Drizzle Studio you have at least four elements so that we can work with somewhat of a grid. So I'm going to go inside of the app folder here And what we have to do now is we have to go inside of the main here and let's create a new folder courses. And inside let's create a new file page.dsx.
And remember to export default the courses page. And let's return a div courses page. I'm going to go ahead and try to go to slash courses. So this arrow and the click on a flag should redirect you to slash courses now. There we go.
You can see how I'm redirected to slash courses. Perfect. So I'm gonna go ahead and style this a bit. I'm gonna give this a class name of full height, max width of 912 pixels, px3 and mx auto. Then inside I'm gonna add an h1 element with language courses title.
Let's style this h1 element by giving it a text to Excel font bold and text neutral 700 There we go, so let me expand this so we can see how it looks like and there we go perfect So now that we have this I want to create a query which is actually gonna fetch our newly added courses from the database. So let's go ahead and inside of our database create a new file queries.ds and let's do export const get courses and make sure you cache this function so import cache from react it's going to be an asynchronous method and let's go ahead and patch the data using await let's call the database from dot slash drizzle dot query dot courses dot find many and very simply return the data And this is supposed to be asynchronous like that. So if you want to, you can go with .slash drizzle or you can use add slash database drizzle depending on how and what you prefer. So we are using cache from react so that we can use this get courses without having to pass the props every time. So if I go ahead and turn this into an asynchronous function and if I do const data await get courses here from database queries now and let's say here I have a list component and I don't want to pass in the props like this right Of course this is perfectly fine to do but let's imagine that I don't want to pass props for any reason.
If I go inside of this list component and if I call this function again getCourses() It's not going to call the database again because of this cache function. So that's why I want us to cache every single query that we are going to write. So that's why I'm doing that. Great! So now let's go ahead and do the following let's go ahead and write json.stringify and pass in the data let's save that and there we go so you can see how I successfully loaded my Spanish, my French, my Croatian and my Italian records from the database.
Perfect. So now we're going to go ahead and create the actual list component, which will render this. So I'm going to go ahead and add a list like that. And the List component is going to accept the courses which is going to be our data or we can actually name it courses, right? And we're going to have an active course ID which for now is going to be hardcoded to 1.
So let's go ahead and inside of the courses folder create a new list.dsx component and inside of here let's mark it as use client because it's going to have some interactive elements. Let's give it a type of props. And here's the cool thing. So now we can finally use the type of courses for our props. So let's write courses, and that's gonna be a type of courses from database schema dot infer select.
And let's go ahead and add an array at the end and we're gonna have an active course ID we can write number because we know that our schema type of ID is serial which is actually a number or you can do well we actually don't have the ID we actually don't have the model prepared for this I'm gonna explain it in a second. So for now, let's just keep number. I wanted to do something with a type of as well, but we are missing one table, which I'm gonna create in a moment once we finish this. So for now, let's just do it like that. And let's export const list here.
Let's sign those props. And let's return a div saying list and let's see if this is broken here so list is not defined so we have to import that from dot slash list and there we go you can see how we no longer have any prop errors so this accepts courses this is the object and this is the array it accepts exactly what we expect so now what I want to do is I want to give this div a class name and I'm going to go ahead and create a grid that I want to display my flags. So padding top is going to be six. It's going to be grid, grid calls two on small or mobile devices. And then on large, we're going to have grid-calls and we're going to go ahead and write in square brackets repeat and then we're gonna pass auto dash fill comma min max open parenthesis auto-fill, min-max, open parenthesis, and in parenthesis we're gonna write 210 pixels, 1fr.
And whenever you are writing inside of this square brackets, make sure you don't accidentally put spaces in between those values. So neither here nor here. You can check if a Tailwind class is correct by hovering on it. So you can see how this custom value, which I've added has perfectly been translated into CSS. If you have the tailwind extension and you hover and yours is not, it probably means that you have a space somewhere.
So just make sure that you have the exact, this is all one line of course. There are no spaces in this place right here. I didn't break this line. This is just my editor settings so that you can see everything all the time so I don't have to scroll in here. Right?
So we have that and let's add GAP4. And now inside of here we're gonna go ahead and actually use these courses. So let's extract the courses and active course ID and in here we're going to map over our courses. Let's get the individual course. And in here, we're going to render a card element.
So let's give it a key of course. Dot ID. And let's give it all the other necessary fields. So id is going to be course.id as well. Title course.title.
Image source is going to be course image source. On click for now is going to be an empty arrow function. Disabled is going to be false. And active is going to be if course ID is equal to active course ID. So now we have to create the card element.
So let's go ahead and create the new file inside of the courses folder called card.dsx let's go ahead and mark this as... Actually we don't have to mark this as client because it already is in a client component so it will not magically become a server component. If you're interested, you can pass server components inside client components, but that is done through the children prop, so not directly like this. So let's go ahead and define the props for this new card component which we've just created. So title is a string, id is a number, image source is a string, onClick is gonna accept an id which is a number and return a void, disabled is gonna be an optional boolean and active is going to be an optional boolean as well.
Let's export const our card element here. Let's go ahead and destructure these props and let's just return a div saying card. Let's go back in our list component and then we can import the card from .slash card like this. And there we go, you can see how my props are perfectly fine with this. Great.
So now let's actually destructure the title, the ID, the image source, the disabled, the onClick and the active prop here. And let's make this look like something. So I'm gonna go ahead and give this div an onclick to open an arrow function and call the onclick and pass in the ID which we have from the prop. It doesn't need a key but it does need a class name and class name is going to be dynamic so open the curly brackets and import the CN from libutils and now in the first parameter we're gonna give it the default classes so the default is gonna be height full, border is gonna be 2, rounded is gonna be extra large, border bottom is going to be 4 pixels, hover is going to use BG black slash 5, cursor is going to be pointer, active is going to be border-bottom-2, flex, flex-column, items-center, justify-between, padding of 3, padding bottom of 6, min height is gonna be 217 pixels and min width is gonna be 200 pixels. Now let's go ahead and add the additional values.
So those are gonna be, if it is disabled, we're gonna write pointer events, none and opacity 50%. And now I'm just gonna zoom out just a bit because this is too zoomed in to be realistic mobile view. So I'm gonna leave it like this and let's go ahead and write a div here inside with a class name of minimum height of 24 pixels. Let's give it a full width, a flex, items, center and justify end. And then Inside, if this class is active, this card, sorry, if this card is active, we're gonna give it a little check mark here.
So inside of here, we're gonna render the check icon from Lucid React. So just make sure you add this import here. So we have the check icon and I'm going to give it a class name of text white and stroke four and I'm going to do that inside of the square brackets and height 4 and width 4. And in here I'm going to give it a class name of RoundedMediumBGGreen600 and I'm going to give it flexItemsCenter, justifyCenter and padding of 1.5. There we go.
So we're going to have a little indicator that one of these courses is currently active. So the first one is currently selected as active because if you remember in our courses page we passed the active course id to be hard-coded to 1. So as you can see in our Drizzle Studio that is this value, Spanish. Alright so now let's actually add a little flag to this card element. So we just wrapped up the active state here.
So go outside of this div which is encapsulating this. And in here we're gonna render an image from next slash image. So it's gonna be a self-closing tag make sure you added the next image import here and we're gonna go ahead and pass in the source to be image source we're gonna give it an alt of title a height of 70 width is gonna be 93.33 and class name is going to be rounded large, drop shadow medium, border, object cover and below that let's add a paragraph which is going to render the title of the course with the text neutral 700 Text center and let's not misspell neutral. Text center, font-bold and margin-top of 3. And there we go.
We have our flags. Perfect. So when you click on them nothing much should happen but you now officially are loading flags directly from your database. So what we have to do next is we have to create a new table inside of our schema which is going to be called user progress and in there we are going to store the current active course ID. So what I want to do before we wrap up is not allow the user, actually, we're gonna do that in the next one.
Yeah, I wanted to do it in this chapter, but I remembered we do need that schema model to even start doing that. Basically, if the user doesn't have any course selected, they are not going to be able to visit any of these pages, learn leaderboard, quests or shop. So they are always going to be redirected to the courses page if they don't have any of the flags. So I'm gonna be calling them flags or courses throughout the tutorial. So if you don't have any of these selected, this is the screen they will see until they click on at least one.
And of course, they will always be able to go back and change them and the progress will be saved. Great, great job.